From: Marcus Boerger Date: Mon, 8 Jan 2007 23:03:41 +0000 (+0000) Subject: - Add initial hash support write/read/verify md5/sha1(default) X-Git-Tag: RELEASE_1_0_0RC1~345 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7093d72b5ef175c0b02232f90b21f13170c3f610;p=php - Add initial hash support write/read/verify md5/sha1(default) --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 7d0022d986..9400481294 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -29,6 +29,8 @@ #include "ext/standard/info.h" #include "ext/standard/url.h" #include "ext/standard/crc32.h" +#include "ext/standard/md5.h" +#include "ext/standard/sha1.h" #include "ext/spl/spl_array.h" #include "ext/spl/spl_directory.h" #include "ext/spl/spl_engine.h" @@ -65,6 +67,12 @@ #define PHAR_HDR_ANY_COMPRESSED 0x0001 #define PHAR_HDR_SIGNATURE 0x0008 +#define PHAR_SIG_MD5 0x0001 +#define PHAR_SIG_SHA1 0x0002 +#define PHAR_SIG_PGP 0x0010 + +#define PHAR_SIG_USE PHAR_SIG_SHA1 + /* flags byte for each file adheres to these bitmasks. All unused values are reserved */ #define PHAR_ENT_COMPRESSION_MASK 0x0F @@ -82,12 +90,14 @@ ZEND_BEGIN_MODULE_GLOBALS(phar) HashTable phar_fname_map; HashTable phar_alias_map; int readonly; + int require_hash; ZEND_END_MODULE_GLOBALS(phar) ZEND_DECLARE_MODULE_GLOBALS(phar) PHP_INI_BEGIN() - STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_SYSTEM, OnUpdateBool, readonly, zend_phar_globals, phar_globals) + STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_SYSTEM, OnUpdateBool, readonly, zend_phar_globals, phar_globals) + STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_SYSTEM, OnUpdateBool, require_hash, zend_phar_globals, phar_globals) PHP_INI_END() #ifndef php_uint16 @@ -591,9 +601,103 @@ static int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alia efree(savebuf); return FAILURE; } + /* The lowest nibble contains the phar wide flags. The any compressed can */ /* be ignored on reading because it is being generated anyways. */ + if (manifest_tag & PHAR_HDR_SIGNATURE) { + unsigned char buf[1024]; + int read_size, len; + php_uint32 sig_flags; + char sig_buf[8], *sig_ptr = sig_buf; + off_t read_len; + + if (-1 == php_stream_seek(fp, -8, SEEK_END) + || (read_len = php_stream_tell(fp)) < 20 + || 8 != php_stream_read(fp, sig_buf, 8) + || memcmp(sig_buf+4, "GBMB", 4)) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + efree(savebuf); + return FAILURE; + } + PHAR_GET_32(sig_ptr, sig_flags); + switch(sig_flags) { + case PHAR_SIG_SHA1: { + unsigned char digest[20], saved[20]; + PHP_SHA1_CTX context; + + php_stream_rewind(fp); + PHP_SHA1Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_SHA1Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_SHA1Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + efree(savebuf); + return FAILURE; + } + + break; + } + case PHAR_SIG_MD5: { + unsigned char digest[16], saved[16]; + PHP_MD5_CTX context; + + php_stream_rewind(fp); + PHP_MD5Init(&context); + read_len -= sizeof(digest); + if (read_len > sizeof(buf)) { + read_size = sizeof(buf); + } else { + read_size = (int)read_len; + } + while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) { + PHP_MD5Update(&context, buf, len); + read_len -= (off_t)len; + if (read_len < read_size) { + read_size = (int)read_len; + } + } + PHP_MD5Final(digest, &context); + + if (read_len > 0 + || php_stream_read(fp, (char*)saved, sizeof(saved)) != sizeof(saved) + || memcmp(digest, saved, sizeof(digest))) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + efree(savebuf); + return FAILURE; + } + + break; + } + default: + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" has a broken signature", fname); + efree(savebuf); + return FAILURE; + } + } else if (PHAR_G(require_hash)) { + php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "phar \"%s\" does not have a signature", fname); + efree(savebuf); + return FAILURE; + } +/*xxx*/ +#define PHAR_SIG_MD5 0x0001 +#define PHAR_SIG_SHA1 0x0002 +#define PHAR_SIG_PGP 0x0010 /* extract alias */ PHAR_GET_32(buffer, tmp_len); if (buffer + tmp_len > endbuffer) { @@ -1511,7 +1615,7 @@ static inline void phar_set_16(char *buffer, int var) /* {{{ */ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ { phar_entry_info *entry; - int alias_len, fname_len, halt_offset, restore_alias_len; + int alias_len, fname_len, halt_offset, restore_alias_len, global_flags = 0; char *buffer, *fname, *alias; char *manifest; off_t manifest_ftell, bufsize; @@ -1670,6 +1774,7 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ file = entry->temp_file; entry->compressed_filesize = copy; entry->flags |= PHAR_ENT_MODIFIED; + global_flags |= PHAR_HDR_ANY_COMPRESSED; } } php_stream_close(compressedfile); @@ -1693,8 +1798,11 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ phar_set_32(manifest+10, 0); data->phar->alias_len = 0; } + + global_flags |= PHAR_HDR_SIGNATURE; + *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF); - *(manifest + 9) = (unsigned char) ((PHAR_API_VERSION) & 0xFF); + *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0) | (global_flags & 0x0F)); /* write the manifest header */ if (14 + data->phar->alias_len != php_stream_write(newfile, manifest, 14 + data->phar->alias_len)) { @@ -1823,6 +1931,50 @@ static int phar_flush(phar_entry_data *data TSRMLS_DC) /* {{{ */ } } + /* append signature */ + if (global_flags & PHAR_HDR_SIGNATURE) { + unsigned char buf[1024]; + int sig_flags = 0, len; + char sig_buf[4]; + + php_stream_rewind(newfile); + + switch(PHAR_SIG_USE) { + case PHAR_SIG_PGP: + /* TODO: currently fall back to sha1,later do both */ + default: + case PHAR_SIG_SHA1: { + unsigned char digest[20]; + PHP_SHA1_CTX context; + + PHP_SHA1Init(&context); + while ((len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_SHA1Update(&context, buf, len); + } + PHP_SHA1Final(digest, &context); + php_stream_write(newfile, digest, sizeof(digest)); + sig_flags |= PHAR_SIG_SHA1; + break; + } + case PHAR_SIG_MD5: { + unsigned char digest[16]; + PHP_MD5_CTX context; + + PHP_MD5Init(&context); + while ((len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) { + PHP_MD5Update(&context, buf, len); + } + PHP_MD5Final(digest, &context); + php_stream_write(newfile, digest, sizeof(digest)); + sig_flags |= PHAR_SIG_MD5; + break; + } + } + phar_set_32(sig_buf, sig_flags); + php_stream_write(newfile, sig_buf, 4); + php_stream_write(newfile, "GBMB", 4); + } + /* finally, close the temp file, rename the original phar, move the temp to the old phar, unlink the old phar, and reload it into memory */ diff --git a/ext/phar/tests/009.phpt b/ext/phar/tests/009.phpt index 7e3acabf0e..b2c9fd7f85 100644 --- a/ext/phar/tests/009.phpt +++ b/ext/phar/tests/009.phpt @@ -2,6 +2,8 @@ Phar::mapPhar too many manifest entries --SKIPIF-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/024.phpt b/ext/phar/tests/024.phpt index 243e70c6c8..97460669c1 100755 --- a/ext/phar/tests/024.phpt +++ b/ext/phar/tests/024.phpt @@ -2,6 +2,8 @@ Phar: phar:// include --SKIPIF-- +--INI-- +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/025.phpt b/ext/phar/tests/025.phpt index bf66256bdc..a591d59fee 100755 --- a/ext/phar/tests/025.phpt +++ b/ext/phar/tests/025.phpt @@ -2,6 +2,8 @@ Phar: phar:// include (repeated names) --SKIPIF-- +--INI-- +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/026.phpt b/ext/phar/tests/026.phpt index 9737c5f1fd..7eb2f90b67 100755 --- a/ext/phar/tests/026.phpt +++ b/ext/phar/tests/026.phpt @@ -2,6 +2,8 @@ Phar: phar:// require from within --SKIPIF-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=1 +--FILE-- + +===DONE=== +--CLEAN-- + +--EXPECTF-- + +Catchable fatal error: Phar::loadPhar(): phar "%sphar_oo_test.phar.php" does not have a signature in %s032.php on line %d diff --git a/ext/phar/tests/create_new_phar.phpt b/ext/phar/tests/create_new_phar.phpt index fe00960a74..2781f0c7bf 100644 --- a/ext/phar/tests/create_new_phar.phpt +++ b/ext/phar/tests/create_new_phar.phpt @@ -4,6 +4,7 @@ Phar: create a completely new phar --INI-- phar.readonly=0 +phar.require_hash=1 --FILE-- --INI-- phar.readonly=1 +phar.require_hash=1 --FILE-- --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/delete_in_phar_b.phpt b/ext/phar/tests/delete_in_phar_b.phpt index c90dd10120..ba18174bbf 100755 --- a/ext/phar/tests/delete_in_phar_b.phpt +++ b/ext/phar/tests/delete_in_phar_b.phpt @@ -4,6 +4,7 @@ Phar: delete a file within a .phar --INI-- phar.readonly=1 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/delete_in_phar_confirm.phpt b/ext/phar/tests/delete_in_phar_confirm.phpt index 7e8d048533..69a802fad2 100644 --- a/ext/phar/tests/delete_in_phar_confirm.phpt +++ b/ext/phar/tests/delete_in_phar_confirm.phpt @@ -4,6 +4,7 @@ Phar: delete a file within a .phar (confirm disk file is changed) --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/open_for_write_existing.phpt b/ext/phar/tests/open_for_write_existing.phpt index b789e941a1..93a1539e93 100644 --- a/ext/phar/tests/open_for_write_existing.phpt +++ b/ext/phar/tests/open_for_write_existing.phpt @@ -4,6 +4,7 @@ Phar: fopen a .phar for writing (existing file) --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/open_for_write_existing_b.phpt b/ext/phar/tests/open_for_write_existing_b.phpt index 1c3e21199f..26631f4864 100755 --- a/ext/phar/tests/open_for_write_existing_b.phpt +++ b/ext/phar/tests/open_for_write_existing_b.phpt @@ -4,6 +4,7 @@ Phar: fopen a .phar for writing (existing file) --INI-- phar.readonly=1 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/open_for_write_newfile.phpt b/ext/phar/tests/open_for_write_newfile.phpt index 585ac80240..5d6922945c 100644 --- a/ext/phar/tests/open_for_write_newfile.phpt +++ b/ext/phar/tests/open_for_write_newfile.phpt @@ -4,6 +4,7 @@ Phar: fopen a .phar for writing (new file) --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/open_for_write_newfile_b.phpt b/ext/phar/tests/open_for_write_newfile_b.phpt index 0c4bd13f7d..38618de80e 100755 --- a/ext/phar/tests/open_for_write_newfile_b.phpt +++ b/ext/phar/tests/open_for_write_newfile_b.phpt @@ -4,6 +4,7 @@ Phar: fopen a .phar for writing (new file) --INI-- phar.readonly=1 +phar.require_hash=0 --FILE-- "; diff --git a/ext/phar/tests/phar_oo_001.phpt b/ext/phar/tests/phar_oo_001.phpt index 8240969a2b..90cf3e991d 100755 --- a/ext/phar/tests/phar_oo_001.phpt +++ b/ext/phar/tests/phar_oo_001.phpt @@ -2,6 +2,8 @@ Phar object: basics --SKIPIF-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- +--INI-- +phar.require_hash=0 --FILE-- --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- --INI-- phar.readonly=1 +phar.require_hash=0 --FILE-- --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- --INI-- phar.readonly=0 +phar.require_hash=0 --FILE-- --INI-- phar.readonly=1 +phar.require_hash=0 --FILE--