[PATCH 4 of 5] (Issue55) Sign a linux installer
Wald Commits
scm-commit at wald.intevation.org
Mon Jul 7 18:56:01 CEST 2014
# HG changeset patch
# User Andre Heinecke <andre.heinecke at intevation.de>
# Date 1404751968 -7200
# Node ID 49168bcb02e2805ace3b14689c48464ea0cf2347
# Parent 438d7c88104ff86df0d069755ba82045d1bf0710
(Issue55) Sign a linux installer
This uses the same RSA key that is used for Windows codesigning
to create an additonal
S:<base64encodedsignature> line.
Signed is everything up to the last \r\n before the S:
line.
The hash algorithm is sha256
diff -r 438d7c88104f -r 49168bcb02e2 ui/createinstallerdialog.cpp
--- a/ui/createinstallerdialog.cpp Mon Jul 07 18:50:06 2014 +0200
+++ b/ui/createinstallerdialog.cpp Mon Jul 07 18:52:48 2014 +0200
@@ -6,6 +6,8 @@
* See LICENSE.txt for details.
*/
#include "createinstallerdialog.h"
+#include "sslhelp.h"
+
#include <QDebug>
#include <QTextEdit>
#include <QDir>
@@ -15,12 +17,15 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QFileDialog>
+#include <QSaveFile>
#include <QSettings>
#include <QStyle>
#include <QApplication>
#include <QMessageBox>
#include <QTemporaryDir>
+#include <polarssl/pk.h>
+
/* Static information used in codesigning */
#ifndef SIGN_HASH
#define SIGN_HASH "sha256"
@@ -32,7 +37,6 @@
#define SIGN_PUBLISHER "TrustBridge Test with ümlaut"
#endif
-
CreateInstallerDialog::CreateInstallerDialog(QMainWindow *parent) :
QDialog(parent),
mProgress(this),
@@ -228,11 +232,46 @@
.arg(binDir.path()));
return;
}
+ /* Sign the linux installer */
+ QDir linuxDir(binDir.path() + "/linux");
+ if (!linuxDir.exists()) {
+ showErrorMessage(tr("Failed to find the directory for linux binaries: %s")
+ .arg(linuxDir.path()));
+ return;
+ }
+ QStringList nameFilter;
+ nameFilter << "*.sh";
+ QStringList candidates = linuxDir.entryList(nameFilter, QDir::Files | QDir::Readable);
+ if (candidates.isEmpty()) {
+ showErrorMessage(tr("Failed to find a readable *.sh file in: %s")
+ .arg(linuxDir.path()));
+ return;
+ }
+ if (candidates.size() > 1) {
+ showErrorMessage(tr("Unexpected additional .sh files in: %s")
+ .arg(linuxDir.path()));
+ return;
+ }
+ mProgress.setLabelText(tr("Signing Linux package..."));
+ mProgress.cancel();
- QTemporaryDir *signedFilesDir = codesignBinaries(binDir.path() + "/windows");
+ QString outFileName = options.value("setupname", "TrustBridge-default.exe"
+ ).toString().replace(".exe", ".sh").arg(QString());
- if (!signedFilesDir) {
+ if (!appendTextSignatureToFile(linuxDir.path() + "/" + candidates.first(),
+ outDir.path() + "/" + outFileName)) {
+ qDebug() << "Failed to sign linux package.";
+ mProgress.close();
+ return;
+ }
+
+ /* The Windows installer */
+
+ mCurrentWorkingDir = codesignBinaries(binDir.path() + "/windows");
+
+ if (!mCurrentWorkingDir) {
/* Error messages should have been shown by the codesign function */
+ mProgress.close();
return;
}
@@ -244,7 +283,7 @@
mNSISProc.setProcessChannelMode(QProcess::MergedChannels);
mNSISProc.setWorkingDirectory(outDir.path());
#ifdef Q_OS_WIN
- arguments << QString::fromLatin1("/Dfiles_dir=") + signedFilesDir->path().replace("/", "\\");
+ arguments << QString::fromLatin1("/Dfiles_dir=") + mCurrentWorkingDir->path().replace("/", "\\");
arguments << "/Dpath_sep=\\";
foreach (const QString &key, keys) {
QString value = options.value(key, QString()).toString();
@@ -255,7 +294,7 @@
arguments << QString::fromLatin1("/D%1=%2").arg(key, value);
}
#else
- arguments << QString::fromLatin1("-Dfiles_dir=") + signedFilesDir->path();
+ arguments << QString::fromLatin1("-Dfiles_dir=") + mCurrentWorkingDir->path();
arguments << "-Dpath_sep=/";
foreach (const QString &key, keys) {
QString value = options.value(key, QString()).toString();
@@ -360,6 +399,64 @@
return target;
}
+bool CreateInstallerDialog::appendTextSignatureToFile(const QString& input,
+ const QString& output) {
+ QFile inFile(input);
+ pk_context pk;
+
+ pk_init(&pk);
+ int ret = pk_parse_keyfile(&pk, mCertFile->text().toLocal8Bit().constData(), "");
+
+ if (ret != 0) {
+ showErrorMessage(tr("Failed to load certificate: %1")
+ .arg(getPolarSSLErrorMsg(ret)));
+ pk_free(&pk);
+ return false;
+ }
+
+ /* Check that it is a 3072 bit RSA key as specified */
+ if (!pk.pk_info || pk_get_size(&pk) != 3072 ||
+ pk.pk_info->type != POLARSSL_PK_RSA) {
+ qDebug() << pk.pk_info->type << "type";
+ qDebug() << POLARSSL_PK_RSA << "rsa";
+ qDebug() << "size " << pk_get_size(&pk);
+ showErrorMessage(tr("Only 3072 bit RSA keys are supported by the current format."));
+ pk_free(&pk);
+ return false;
+ }
+
+ if (!inFile.open(QIODevice::ReadOnly)) {
+ showErrorMessage(tr("Failed to open input file: %1").arg(inFile.fileName()));
+ pk_free(&pk);
+ return false;
+ }
+
+ const QByteArray inputContent = inFile.readAll(); // Memory is cheap :)
+ inFile.close();
+
+ if (inputContent.isEmpty()) {
+ showErrorMessage(tr("Failed to read input file: %1").arg(inFile.fileName()));
+ pk_free(&pk);
+ return false;
+ }
+
+ const QByteArray signature = rsaSignSHA256Hash(sha256sum(inputContent), &pk);
+
+ pk_free(&pk);
+ if (signature.size() != 3072 / 8) {
+ qDebug() << "Signature creation returned signature of invalid size.";
+ return false;
+ }
+
+ QSaveFile outFile(output);
+ outFile.open(QIODevice::WriteOnly);
+ outFile.write(inputContent);
+ outFile.write("\r\nS:");
+ outFile.write(signature.toBase64());
+
+ return outFile.commit();
+}
+
FinishedDialog::FinishedDialog(QDialog *parent,
QString msg, QString details, bool isErr):
QDialog(parent)
diff -r 438d7c88104f -r 49168bcb02e2 ui/createinstallerdialog.h
--- a/ui/createinstallerdialog.h Mon Jul 07 18:50:06 2014 +0200
+++ b/ui/createinstallerdialog.h Mon Jul 07 18:52:48 2014 +0200
@@ -91,6 +91,19 @@
*/
bool signFile(QString filePath);
+ /**@brief Append a base64 encoded sha256 RSA signature to a file.
+ *
+ * The format of the added signature line will be:
+ * S:<signature>\r\n
+ * For the signature the key in mCertFile is used.
+ *
+ * @param[in] input The absolute path of the file to sign
+ * @param[out] output The absolute path of the file to write
+ *
+ * @returns true on success, false on failure
+ */
+ bool appendTextSignatureToFile(const QString& input, const QString& output);
+
/* Slots for the creator process */
void processError(QProcess::ProcessError error);
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
More information about the Trustbridge-commits
mailing list