# HG changeset patch # User Andre Heinecke # 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: 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 #include #include @@ -15,12 +17,15 @@ #include #include #include +#include #include #include #include #include #include +#include + /* 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:\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);