diff --git a/PharUtil/RemotePharVerifier.php b/PharUtil/RemotePharVerifier.php
index 24e909c..113eb58 100644
--- a/PharUtil/RemotePharVerifier.php
+++ b/PharUtil/RemotePharVerifier.php
@@ -160,13 +160,14 @@ protected function assertVerified($local_path) {
if (!copy($this->pub_key_file, $this->getPubkeyFilename($local_path))) {
throw new RuntimeException("Error copying public key file!");
}
- try {
- $this->verifyPharSignature($local_path);
- } catch (Exception $e) {
- $this->doDelete($local_path); // delete offending files
- throw $e;
- }
}
+ try {
+ $this->verifyPharSignature($local_path);
+ } catch (Exception $e) {
+ $this->doDelete($local_path); // delete offending files
+ throw $e;
+ }
+
return true;
}
@@ -228,7 +229,7 @@ protected function verifyPharSignature($local_path) {
$sig = $phar->getSignature();
unset($phar);
- if ($sig['hash_type'] !== 'OpenSSL') {
+ if ($this->pub_key_file && $sig['hash_type'] !== 'OpenSSL') {
throw new PharUtil_SignatureVerificationException("This phar is not signed with OpenSSL!");
}
} catch (UnexpectedValueException $e) {
diff --git a/package.xml b/package.xml
index 1b61f7d..700c162 100644
--- a/package.xml
+++ b/package.xml
@@ -16,7 +16,7 @@
2010-08-06
- 0.2.0
+ 0.3.0
0.1
@@ -49,6 +49,7 @@
+
@@ -95,6 +96,15 @@
+
+
+
+
+
+
+
+
+
@@ -132,18 +142,35 @@
+
+
+
+
+
+
+ 0.3
+ 0.1
+
+
+ beta
+ beta
+
+ 2010-08-06
+ MIT
+ Added phar-verify toolset, small changes
+
0.2
0.1
diff --git a/phar-build.php b/phar-build.php
index eff3054..f760c96 100644
--- a/phar-build.php
+++ b/phar-build.php
@@ -20,7 +20,6 @@
'name' => 'phar-build',
));
-// add an option to make the program verbose
$parser->addOption('src', array(
'short_name' => '-s',
'long_name' => '--src',
diff --git a/phar-extract.php b/phar-extract.php
index 28e6229..8054a27 100644
--- a/phar-extract.php
+++ b/phar-extract.php
@@ -38,7 +38,6 @@
'description' => "Input Phar archive filename e.g. phar.phar",
));
-// add an option to make the program verbose
$parser->addArgument('destination', array(
'action' => 'StoreString',
'description' => "Destination directory"
@@ -104,7 +103,7 @@
throw new Exception("Phar writing support is disabled in this PHP installation, set phar.readonly=0 in php.ini!");
}
echo "Extracting {$files_count} file(s) to: {$args['destination']}..." . PHP_EOL;
- $phar->ExtractTo($args['destination'], null, true);
+ $phar->extractTo($args['destination'], null, true);
}
if ($options['public']) {
diff --git a/phar-verify.bat b/phar-verify.bat
new file mode 100644
index 0000000..e644aad
--- /dev/null
+++ b/phar-verify.bat
@@ -0,0 +1,8 @@
+@ECHO OFF
+if "%PHPBIN%" == "" set PHPBIN="@php_bin@"
+if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
+GOTO RUN
+:USE_PEAR_PATH
+set PHPBIN="%PHP_PEAR_PHP_BIN%"
+:RUN
+%PHPBIN% "@bin_dir@\phar-verify" %*
diff --git a/phar-verify.php b/phar-verify.php
new file mode 100644
index 0000000..336483f
--- /dev/null
+++ b/phar-verify.php
@@ -0,0 +1,94 @@
+#!/usr/bin/env php
+
+ * @package PharUtil
+ */
+
+// Include the Console_CommandLine package.
+require_once 'Console/CommandLine.php';
+require_once 'PharUtil/RemotePharVerifier.php';
+
+// create the parser
+$parser = new Console_CommandLine(array(
+ 'description' => 'Verify Phar archive signature using a public key file',
+ 'version' => '@package_version@',
+ 'name' => 'phar-verify',
+));
+
+$parser->addOption('public', array(
+ 'short_name' => '-P',
+ 'long_name' => '--public',
+ 'action' => 'StoreString',
+ 'default' => './cert/pub.pem',
+ 'description' => "Public key file (PEM) to verify signature\n(./cert/pub.pem by default)"
+));
+
+$parser->addOption('nosign', array(
+ 'short_name' => '-n',
+ 'long_name' => '--ns',
+ 'action' => 'StoreTrue',
+ 'description' => 'Archive is not signed, don\'t require an OpenSSL signature'
+));
+
+$parser->addOption('temp', array(
+ 'short_name' => '-t',
+ 'long_name' => '--temp',
+ 'action' => 'StoreString',
+ 'description' => 'Temporary directory (' . sys_get_temp_dir() . ' by default)',
+));
+
+$parser->addArgument('phar', array(
+ 'action' => 'StoreString',
+ 'description' => "Input Phar archive URI e.g.\n/path/to/local/phar.phar or http://path/to/remote/phar.phar",
+));
+
+// run the parser
+try {
+ $result = $parser->parse();
+} catch (Exception $exc) {
+ $parser->displayError($exc->getMessage());
+}
+
+$options = $result->options;
+$args = $result->args;
+
+echo $parser->name . ' ' . $parser->version . PHP_EOL . PHP_EOL;
+
+// validate parameters
+if (substr($args['phar'], -5) !== '.phar') {
+ $parser->displayError("Input Phar must have .phar extension, {$args['phar']} given.", 2);
+}
+
+if ($options['nosign']) {
+ $options['public'] = null; // no public key
+}
+
+if ($options['public']) {
+ if (!file_exists($options['public']) || !is_readable($options['public'])) {
+ $parser->displayError("Public key in '{$options['public']}' does not exist or is not readable.", 4);
+ }
+}
+
+if (!$options['temp']) {
+ $options['temp'] = sys_get_temp_dir();
+}
+
+try {
+ echo "Verifying Phar archive: {$args['phar']}..." . PHP_EOL;
+
+ $v = new PharUtil_RemotePharVerifier($options['temp'], $options['temp'], $options['public']);
+
+ $v->verify($args['phar']);
+
+ echo "Phar archive successfully verified." . PHP_EOL;
+} catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . PHP_EOL;
+ exit(1);
+}
+
+
+echo PHP_EOL . "All done, exiting." . PHP_EOL;
\ No newline at end of file
diff --git a/test/PharUtil/RemotePharVerifierTest.php b/test/PharUtil/RemotePharVerifierTest.php
index e3bec8c..c7b7069 100644
--- a/test/PharUtil/RemotePharVerifierTest.php
+++ b/test/PharUtil/RemotePharVerifierTest.php
@@ -104,10 +104,12 @@ public function testFetchCleansUpOnFailure($file) {
}
$this->fail("PharUtil_SignatureVerificationException was not thrown");
}
+
public function invalidFiles() {
return array(
array('wrongsig.phar'),
array('nosig.phar'),
+ array('nosigmodified.phar'),
array('modified.phar'),
array('test.phar.gz'),
);
@@ -120,7 +122,7 @@ public function testModifiedPharsAreInvalid() {
$v->fetch($this->remote_dir . 'modified.phar');
}
- public function testNoPubkeyChecking() {
+ public function testNoPubkeyWillPassNotSignedPhars() {
// no public key given
$v = new PharUtil_RemotePharVerifier($this->fetch_dir, $this->verified_dir, null);
@@ -128,20 +130,41 @@ public function testNoPubkeyChecking() {
$this->assertFileExists($ok);
$this->assertFileEquals($this->remote_dir . 'nosig.phar', $ok);
- $ok = $v->fetch($this->remote_dir . 'wrongsig.phar');
- $this->assertFileExists($ok);
- $this->assertFileEquals($this->remote_dir . 'wrongsig.phar', $ok);
-
- $ok = $v->fetch($this->remote_dir . 'modified.phar');
- $this->assertFileExists($ok);
- $this->assertFileEquals($this->remote_dir . 'modified.phar', $ok);
-
// gzips are ok withot pubkey verification
$ok = $v->fetch($this->remote_dir . 'test.phar.gz');
$this->assertFileExists($ok);
$this->assertFileEquals($this->remote_dir . 'test.phar.gz', $ok);
}
+ /**
+ * @dataProvider openSslFiles
+ */
+ public function testNoPubkeyWillErrorOnAllSignedPhars($file) {
+ // no public key given
+ $v = new PharUtil_RemotePharVerifier($this->fetch_dir, $this->verified_dir, null);
+
+ // this will pass (thankyou Phar :( )
+ $this->setExpectedException('PharUtil_SignatureVerificationException');
+ $ok = $v->fetch($this->remote_dir . $file);
+ }
+
+ public function openSslFiles() {
+ return array(
+ array('wrongsig.phar'),
+ array('modified.phar'),
+ array('test.phar'),
+ );
+ }
+
+ public function testNoPubkeyWillCheckOtherChecksums() {
+ // no public key given
+ $v = new PharUtil_RemotePharVerifier($this->fetch_dir, $this->verified_dir, null);
+
+ // simulate transfer error (SHA-1 checksum, but file is modified)
+ $this->setExpectedException('PharUtil_SignatureVerificationException');
+ $ok = $v->fetch($this->remote_dir . 'nosigmodified.phar');
+ }
+
/**
* @dataProvider invalidFilenames
*/
diff --git a/test/PharUtil/data/phar/nosigmodified.phar b/test/PharUtil/data/phar/nosigmodified.phar
new file mode 100644
index 0000000..74c4e73
Binary files /dev/null and b/test/PharUtil/data/phar/nosigmodified.phar differ