|
|
|
@ -1,8 +1,26 @@
|
|
|
|
|
#include "unpack.hh"
|
|
|
|
|
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <system_error>
|
|
|
|
|
#include <archive.h>
|
|
|
|
|
#include <archive_entry.h>
|
|
|
|
|
#include <cryptopp/pssr.h>
|
|
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
// FIXME: name collision possible
|
|
|
|
|
static char *mkdtemp(char *template)
|
|
|
|
|
{
|
|
|
|
|
if (_mktemp(template) == nullptr)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
if (_mkdir(template))
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
return template;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace SignedPackage {
|
|
|
|
|
static bool path_empty(std::string path)
|
|
|
|
@ -28,10 +46,18 @@ namespace SignedPackage {
|
|
|
|
|
std::filesystem::path path = std::filesystem::temp_directory_path() / "spXXXXXXXXXXXX";
|
|
|
|
|
|
|
|
|
|
size_t size = ((std::string) path).size();
|
|
|
|
|
|
|
|
|
|
char* buffer = new char[size + 1];
|
|
|
|
|
::memcpy(buffer, ((std::string) path).c_str(), size);
|
|
|
|
|
buffer[size] = 0;
|
|
|
|
|
::mkdtemp(buffer);
|
|
|
|
|
|
|
|
|
|
char *p = mkdtemp(buffer);
|
|
|
|
|
if (p == nullptr) {
|
|
|
|
|
delete[] buffer;
|
|
|
|
|
throw std::filesystem::filesystem_error(::strerror(errno),
|
|
|
|
|
std::error_code(errno, std::system_category()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path = buffer;
|
|
|
|
|
delete[] buffer;
|
|
|
|
|
|
|
|
|
@ -40,35 +66,13 @@ namespace SignedPackage {
|
|
|
|
|
|
|
|
|
|
void extract_archive(
|
|
|
|
|
std::string pkg_path,
|
|
|
|
|
std::string target_path
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::filesystem::path extract_deployment_archive(
|
|
|
|
|
std::string pkg_path,
|
|
|
|
|
CryptoPP::PublicKey& deployment_key
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
std::filesystem::path target_path = mktempdir();
|
|
|
|
|
extract_archive(pkg_path, target_path);
|
|
|
|
|
|
|
|
|
|
return target_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void install_if_location_empty(
|
|
|
|
|
CryptoPP::PublicKey& deployment_key,
|
|
|
|
|
CryptoPP::PrivateKey& provisioning_key,
|
|
|
|
|
std::string pkg_path,
|
|
|
|
|
std::string target_path
|
|
|
|
|
std::string target_path,
|
|
|
|
|
std::vector< std::string > filenames
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
std::string cwd = std::filesystem::current_path();
|
|
|
|
|
std::string tmp_path = extract_deployment_archive(pkg_path, deployment_key);
|
|
|
|
|
|
|
|
|
|
ensure_target_path(target_path);
|
|
|
|
|
std::filesystem::current_path(target_path);
|
|
|
|
|
|
|
|
|
|
struct archive *a = ::archive_read_new();
|
|
|
|
|
|
|
|
|
|
::archive_read_support_filter_all(a);
|
|
|
|
@ -87,7 +91,8 @@ namespace SignedPackage {
|
|
|
|
|
std::string pathname{::archive_entry_pathname(entry)};
|
|
|
|
|
|
|
|
|
|
int n = 0;
|
|
|
|
|
if (pathname == "DIST.A" || pathname == "DIST.KEY" || pathname == "DIST.SIG") {
|
|
|
|
|
if (!filenames.size() || std::find(filenames.begin(),
|
|
|
|
|
filenames.end(), pathname) != filenames.end()) {
|
|
|
|
|
do {
|
|
|
|
|
r = archive_read_extract(a, entry,
|
|
|
|
|
ARCHIVE_EXTRACT_ACL |
|
|
|
|
@ -110,7 +115,7 @@ namespace SignedPackage {
|
|
|
|
|
}
|
|
|
|
|
++n;
|
|
|
|
|
}
|
|
|
|
|
if (n < 3) {
|
|
|
|
|
if (filenames.size() && n != filenames.size()) {
|
|
|
|
|
::archive_read_close(a);
|
|
|
|
|
::archive_read_free(a);
|
|
|
|
|
std::filesystem::current_path(cwd);
|
|
|
|
@ -123,6 +128,54 @@ namespace SignedPackage {
|
|
|
|
|
std::filesystem::current_path(cwd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool check_signature(
|
|
|
|
|
std::filesystem::path file,
|
|
|
|
|
std::filesystem::path sig,
|
|
|
|
|
CryptoPP::PublicKey& key
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
CryptoPP::RSASS<CryptoPP::PSS, CryptoPP::SHA256>::Verifier verifier(key);
|
|
|
|
|
|
|
|
|
|
CryptoPP::SignatureVerificationFilter verificationFilter(verifier,
|
|
|
|
|
nullptr,
|
|
|
|
|
CryptoPP::SignatureVerificationFilter::SIGNATURE_AT_BEGIN
|
|
|
|
|
| CryptoPP::SignatureVerificationFilter::THROW_EXCEPTION);
|
|
|
|
|
|
|
|
|
|
CryptoPP::FileSource fileSource(((std::string) file).c_str(), false,
|
|
|
|
|
new CryptoPP::Redirector(verificationFilter));
|
|
|
|
|
|
|
|
|
|
CryptoPP::FileSource signatureSource(((std::string) sig).c_str(), false,
|
|
|
|
|
new CryptoPP::Redirector(verificationFilter));
|
|
|
|
|
|
|
|
|
|
signatureSource.PumpAll();
|
|
|
|
|
fileSource.PumpAll();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::filesystem::path extract_deployment_archive(
|
|
|
|
|
CryptoPP::PublicKey& deployment_key,
|
|
|
|
|
std::string pkg_path
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
std::filesystem::path target_path = mktempdir();
|
|
|
|
|
extract_archive(pkg_path, target_path, { "DIST.A", "DIST.KEY", "DIST.SIG" });
|
|
|
|
|
check_signature(target_path / "DIST.A", target_path / "DIST.SIG", deployment_key);
|
|
|
|
|
|
|
|
|
|
return target_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void install_if_location_empty(
|
|
|
|
|
CryptoPP::PublicKey& deployment_key,
|
|
|
|
|
CryptoPP::PrivateKey& provisioning_key,
|
|
|
|
|
std::string pkg_path,
|
|
|
|
|
std::string target_path
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
std::string tmp_path = extract_deployment_archive(deployment_key, pkg_path);
|
|
|
|
|
ensure_target_path(target_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void provision_system(
|
|
|
|
|
pEp::UpdateClient::product p,
|
|
|
|
|
pEp::UpdateClient::PublicKey update_key,
|
|
|
|
|