mirror of
https://github.com/php/php-src.git
synced 2026-04-27 01:48:26 +02:00
full refactor of signatures complete - now to implement them for tar as a starting point
This commit is contained in:
+34
-184
@@ -24,25 +24,6 @@
|
||||
#include "SAPI.h"
|
||||
#include "func_interceptors.h"
|
||||
|
||||
#ifdef PHAR_HAVE_OPENSSL
|
||||
|
||||
/* OpenSSL includes */
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PHAR_HAVE_OPENSSL
|
||||
static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC);
|
||||
#endif
|
||||
static void destroy_phar_data(void *pDest);
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(phar)
|
||||
@@ -604,25 +585,6 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR
|
||||
}
|
||||
/* }}}*/
|
||||
|
||||
static const char hexChars[] = "0123456789ABCDEF";
|
||||
|
||||
static int phar_hex_str(const char *digest, size_t digest_len, char ** signature)
|
||||
{
|
||||
int pos = -1;
|
||||
size_t len = 0;
|
||||
|
||||
TSRMLS_FETCH();
|
||||
|
||||
*signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
|
||||
|
||||
for (; len < digest_len; ++len) {
|
||||
(*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
|
||||
(*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
|
||||
}
|
||||
(*signature)[++pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not check for a previously opened phar in the cache.
|
||||
*
|
||||
@@ -2917,169 +2879,57 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
|
||||
|
||||
/* append signature */
|
||||
if (global_flags & PHAR_HDR_SIGNATURE) {
|
||||
unsigned char buf[1024];
|
||||
int sig_flags = 0, sig_len;
|
||||
char sig_buf[4];
|
||||
|
||||
php_stream_rewind(newfile);
|
||||
|
||||
if (phar->signature) {
|
||||
efree(phar->signature);
|
||||
phar->signature = NULL;
|
||||
}
|
||||
|
||||
switch(phar->sig_flags) {
|
||||
#if HAVE_HASH_EXT
|
||||
case PHAR_SIG_SHA512: {
|
||||
unsigned char digest[64];
|
||||
PHP_SHA512_CTX context;
|
||||
|
||||
PHP_SHA512Init(&context);
|
||||
while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA512Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA512Final(digest, &context);
|
||||
php_stream_write(newfile, (char *) digest, sizeof(digest));
|
||||
sig_flags |= PHAR_SIG_SHA512;
|
||||
phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_SHA256: {
|
||||
unsigned char digest[32];
|
||||
PHP_SHA256_CTX context;
|
||||
|
||||
PHP_SHA256Init(&context);
|
||||
while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA256Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA256Final(digest, &context);
|
||||
php_stream_write(newfile, (char *) digest, sizeof(digest));
|
||||
sig_flags |= PHAR_SIG_SHA256;
|
||||
phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case PHAR_SIG_SHA512:
|
||||
case PHAR_SIG_SHA256:
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
#if !HAVE_HASH_EXT
|
||||
case PHAR_SIG_SHA512:
|
||||
case PHAR_SIG_SHA256:
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
#endif
|
||||
case PHAR_SIG_OPENSSL: {
|
||||
int siglen;
|
||||
unsigned char *sigbuf;
|
||||
#ifdef PHAR_HAVE_OPENSSL
|
||||
BIO *in;
|
||||
EVP_PKEY *key;
|
||||
EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
|
||||
EVP_MD_CTX md_ctx;
|
||||
|
||||
if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "phar \"%s\" openssl signature cannot be created, openssl not loaded", phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
|
||||
default: {
|
||||
char *digest;
|
||||
int digest_len;
|
||||
|
||||
if (in == NULL) {
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
|
||||
if (error) {
|
||||
char *save = *error;
|
||||
spprintf(error, 0, "phar error: unable to write signature: %s", save);
|
||||
efree(save);
|
||||
}
|
||||
efree(digest);
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
return EOF;
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested openssl signature", entry->filename, phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
|
||||
|
||||
BIO_free(in);
|
||||
siglen = EVP_PKEY_size(key);
|
||||
sigbuf = emalloc(siglen + 1);
|
||||
|
||||
EVP_SignInit(&md_ctx, mdtype);
|
||||
while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
|
||||
EVP_SignUpdate(&md_ctx, buf, sig_len);
|
||||
}
|
||||
if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
|
||||
efree(sigbuf);
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
php_stream_write(newfile, digest, digest_len);
|
||||
efree(digest);
|
||||
if (phar->sig_flags == PHAR_SIG_OPENSSL) {
|
||||
phar_set_32(sig_buf, digest_len);
|
||||
php_stream_write(newfile, sig_buf, 4);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
break;
|
||||
}
|
||||
sigbuf[siglen] = '\0';
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
#else
|
||||
sigbuf = NULL;
|
||||
siglen = 0;
|
||||
php_stream_seek(newfile, 0, SEEK_END);
|
||||
if (FAILURE == phar_call_openssl_signverify(1, newfile, php_stream_tell(newfile), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
|
||||
if (closeoldfile) {
|
||||
php_stream_close(oldfile);
|
||||
}
|
||||
php_stream_close(newfile);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
#endif
|
||||
sig_flags |= PHAR_SIG_OPENSSL;
|
||||
phar->sig_len = phar_hex_str((const char *)sigbuf, siglen, &phar->signature);
|
||||
php_stream_write(newfile, (char *) sigbuf, siglen);
|
||||
efree(sigbuf);
|
||||
phar_set_32(sig_buf, siglen);
|
||||
php_stream_write(newfile, sig_buf, 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case PHAR_SIG_SHA1: {
|
||||
unsigned char digest[20];
|
||||
PHP_SHA1_CTX context;
|
||||
|
||||
PHP_SHA1Init(&context);
|
||||
while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA1Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA1Final(digest, &context);
|
||||
php_stream_write(newfile, (char *) digest, sizeof(digest));
|
||||
sig_flags |= PHAR_SIG_SHA1;
|
||||
phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_MD5: {
|
||||
unsigned char digest[16];
|
||||
PHP_MD5_CTX context;
|
||||
|
||||
PHP_MD5Init(&context);
|
||||
while ((sig_len = php_stream_read(newfile, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_MD5Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_MD5Final(digest, &context);
|
||||
php_stream_write(newfile, (char *) digest, sizeof(digest));
|
||||
sig_flags |= PHAR_SIG_MD5;
|
||||
phar->sig_len = phar_hex_str((const char*)digest, sizeof(digest), &phar->signature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
phar_set_32(sig_buf, sig_flags);
|
||||
phar_set_32(sig_buf, phar->sig_flags);
|
||||
php_stream_write(newfile, sig_buf, 4);
|
||||
php_stream_write(newfile, "GBMB", 4);
|
||||
phar->sig_flags = sig_flags;
|
||||
}
|
||||
|
||||
/* finally, close the temp file, rename the original phar,
|
||||
|
||||
Binary file not shown.
@@ -421,6 +421,7 @@ int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_D
|
||||
int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC);
|
||||
int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
|
||||
int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC);
|
||||
int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC);
|
||||
|
||||
/* utility functions */
|
||||
char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC);
|
||||
|
||||
@@ -2759,6 +2759,9 @@ PHP_METHOD(Phar, getSignature)
|
||||
PHAR_ARCHIVE_OBJECT();
|
||||
|
||||
if (phar_obj->arc.archive->signature) {
|
||||
char *unknown;
|
||||
int unknown_len;
|
||||
|
||||
array_init(return_value);
|
||||
add_assoc_stringl(return_value, "hash", phar_obj->arc.archive->signature, phar_obj->arc.archive->sig_len, 1);
|
||||
switch(phar_obj->arc.archive->sig_flags) {
|
||||
@@ -2777,6 +2780,10 @@ PHP_METHOD(Phar, getSignature)
|
||||
case PHAR_SIG_OPENSSL:
|
||||
add_assoc_stringl(return_value, "hash_type", "OpenSSL", 7, 1);
|
||||
break;
|
||||
default:
|
||||
unknown_len = spprintf(&unknown, 0, "Unknown (%d)", phar_obj->arc.archive->sig_flags);
|
||||
add_assoc_stringl(return_value, "hash_type", unknown, unknown_len, 0);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
|
||||
+145
-8
@@ -1340,12 +1340,10 @@ phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, in
|
||||
|
||||
static const char hexChars[] = "0123456789ABCDEF";
|
||||
|
||||
static int phar_hex_str(const char *digest, size_t digest_len, char ** signature)
|
||||
static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC)
|
||||
{
|
||||
int pos = -1;
|
||||
size_t len = 0;
|
||||
|
||||
TSRMLS_FETCH();
|
||||
|
||||
*signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
|
||||
|
||||
@@ -1568,7 +1566,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
#endif
|
||||
|
||||
*signature_len = phar_hex_str((const char*)sig, sig_len, signature);
|
||||
*signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
|
||||
}
|
||||
break;
|
||||
#if HAVE_HASH_EXT
|
||||
@@ -1599,7 +1597,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_SHA256: {
|
||||
@@ -1629,7 +1627,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
@@ -1667,7 +1665,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_MD5: {
|
||||
@@ -1697,7 +1695,7 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature);
|
||||
*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1709,3 +1707,142 @@ int phar_verify_signature(php_stream *fp, size_t end_of_phar, int sig_type, char
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
unsigned char buf[1024];
|
||||
int sig_len;
|
||||
|
||||
php_stream_rewind(fp);
|
||||
|
||||
if (phar->signature) {
|
||||
efree(phar->signature);
|
||||
phar->signature = NULL;
|
||||
}
|
||||
|
||||
switch(phar->sig_flags) {
|
||||
#if HAVE_HASH_EXT
|
||||
case PHAR_SIG_SHA512: {
|
||||
unsigned char digest[64];
|
||||
PHP_SHA512_CTX context;
|
||||
|
||||
PHP_SHA512Init(&context);
|
||||
while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA512Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA512Final(digest, &context);
|
||||
*signature = estrndup((char *) digest, 64);
|
||||
*signature_length = 64;
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_SHA256: {
|
||||
unsigned char digest[32];
|
||||
PHP_SHA256_CTX context;
|
||||
|
||||
PHP_SHA256Init(&context);
|
||||
while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA256Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA256Final(digest, &context);
|
||||
*signature = estrndup((char *) digest, 32);
|
||||
*signature_length = 32;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case PHAR_SIG_SHA512:
|
||||
case PHAR_SIG_SHA256:
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
|
||||
}
|
||||
return FAILURE;
|
||||
#endif
|
||||
case PHAR_SIG_OPENSSL: {
|
||||
int siglen;
|
||||
unsigned char *sigbuf;
|
||||
#ifdef PHAR_HAVE_OPENSSL
|
||||
BIO *in;
|
||||
EVP_PKEY *key;
|
||||
EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
|
||||
EVP_MD_CTX md_ctx;
|
||||
|
||||
if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
|
||||
if (error) {
|
||||
spprintf(error, 0, "phar \"%s\" openssl signature cannot be created, openssl not loaded", phar->fname);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
|
||||
|
||||
if (in == NULL) {
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
|
||||
|
||||
BIO_free(in);
|
||||
siglen = EVP_PKEY_size(key);
|
||||
sigbuf = emalloc(siglen + 1);
|
||||
|
||||
EVP_SignInit(&md_ctx, mdtype);
|
||||
while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
|
||||
EVP_SignUpdate(&md_ctx, buf, sig_len);
|
||||
}
|
||||
if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
|
||||
efree(sigbuf);
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
sigbuf[siglen] = '\0';
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
#else
|
||||
sigbuf = NULL;
|
||||
siglen = 0;
|
||||
php_stream_seek(fp, 0, SEEK_END);
|
||||
if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
|
||||
if (error) {
|
||||
spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
#endif
|
||||
*signature = (char *) sigbuf;
|
||||
*signature_length = siglen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
phar->sig_flags = PHAR_SIG_SHA1;
|
||||
case PHAR_SIG_SHA1: {
|
||||
unsigned char digest[20];
|
||||
PHP_SHA1_CTX context;
|
||||
|
||||
PHP_SHA1Init(&context);
|
||||
while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_SHA1Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_SHA1Final(digest, &context);
|
||||
*signature = estrndup((char *) digest, 20);
|
||||
*signature_length = 20;
|
||||
break;
|
||||
}
|
||||
case PHAR_SIG_MD5: {
|
||||
unsigned char digest[16];
|
||||
PHP_MD5_CTX context;
|
||||
|
||||
PHP_MD5Init(&context);
|
||||
while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
|
||||
PHP_MD5Update(&context, buf, sig_len);
|
||||
}
|
||||
PHP_MD5Final(digest, &context);
|
||||
*signature = estrndup((char *) digest, 16);
|
||||
*signature_length = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
Reference in New Issue
Block a user