I have a php
web application that allows our users to download our software installer setup.exe
.
We've just started signing our code, both the the installer and the applications within it, which is all fine. However when I upload this installer to our web server, and download it through the php
web application, setup.exe
is no longer digitally signed! It's as if it was never signed in the first place.
Here's what I've tried:
[right click] -> [properties]
shows that setup.exe
is not code signed. However setup.exe
is the expected version.setup.exe
directly from the web server through the cpanel
File Manager and this is fine - setup.exe
is digitally signed and the expected version.setup.exe
from the web site via different browsers (firefox, edge) result in the same behaviour.EDIT
setup.exe
file to a public area on the site, and downloading it directly through the browser - works perfectly. All I can think is that the issue has to be in how PHP is serving the application to the browser.I thought the HTTP headers or the PHP download function we have written might be related to the problem.
Our generic include.php
file has the following headers to prevent caching:
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Fri, 01 Jan 2016 01:00:00 GMT"); // a date in the past
And this is our download function:
function DownloadFile($file, $filename) {
// check if file exists and write header info and output file
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: application/x-msdownload');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
return true;
}
else {
// file does not exist
return false;
}
}
Which is primarily from the readfile()
example on php.net. Are there any red flags here? What's going on?
The issue was caused by the way the web application serves the file following a header redirect to the same page - the page itself also serving other data as content.
After the call to DownloadFile()
the rest of the page, including HTML content etc, was sent as part of the file - resulting in the additional data corrupting the digital signature.
The solution was to force the script to exit after the file was sent.
$file = $_SERVER['DOCUMENT_ROOT'] . '/../product/release/' . $path;
DownloadFile($file, "ProductInstaller.exe");
exit; // prevent the rest of the page from being sent as part of the file