# HG changeset patch # User Andre Heinecke # Date 1403702184 -7200 # Node ID 129e611eaf502394b9de62bcf4bce99e3b1e5c4f # Parent e41a2537b84d7a93abc36960541484c6e7ef90e1# Parent 39f03316f675497bbd3d317ca863bad8b55fe4b2 Merge branch trustbridge-refactor diff -r 39f03316f675 -r 129e611eaf50 .hgtags --- a/.hgtags Wed Jun 25 14:56:19 2014 +0200 +++ b/.hgtags Wed Jun 25 15:16:24 2014 +0200 @@ -1,1 +1,2 @@ 421b69eeffe31d9d2ed5c6f6eb45c3856d8323ae 0.6 +10f0b9ceb29d60232845ed25438f886c4058de54 0.65 diff -r 39f03316f675 -r 129e611eaf50 CMakeLists.txt --- a/CMakeLists.txt Wed Jun 25 14:56:19 2014 +0200 +++ b/CMakeLists.txt Wed Jun 25 15:16:24 2014 +0200 @@ -99,6 +99,8 @@ add_dependencies(static_check flawfinder) endif (FLAWFINDER_PATH) +add_subdirectory(common) + add_subdirectory(cinst) if(Qt5Widgets_FOUND) add_subdirectory(ui) @@ -106,8 +108,6 @@ message(STATUS "WARNING: Could not find qt. GUI parts will not be built.") endif() -add_subdirectory(common) - # Documentation configure_file (doc/Doxyfile.in doc/Doxyfile) add_subdirectory(doc) diff -r 39f03316f675 -r 129e611eaf50 INSTALL --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/INSTALL Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,146 @@ +Installation Instructions +************************* + +For Debian based GNU / Linux +============================ +Tested development platform: Ubuntu 13.10. + +The following commands build qt5 and polarssl which are dependencies of the Software. +For build dependencies please refer to the Qt documentation +( qtbase/src/plugins/platforms/xcb/README ). +Polarssl needs cmake and build-essentials. + + export YOURPREFIX= + export PATH=$YOURPREFIX/bin:$PATH + + curl https://download.qt-project.org/official_releases/qt/5.3/5.3.0/single/qt-everywhere-opensource-src-5.3.0.tar.xz.mirrorlist | grep SHA-256 + +e6f47e69a5ce707452dd4bad1fd1919201a71e88be1b06afe1d302a3935daf1f + + http://qt-mirror.dannhauer.de/official_releases/qt/5.3/5.3.0/single/qt-everywhere-opensource-src-5.3.0.tar.xz + + sha256sum qt-everywhere-opensource-src-5.3.0.tar.xz + + tar -xvmlf qt-everywhere-opensource-src-5.3.0.tar.xz + + cd qt-everywhere-opensource-src-5.3.0/qtbase + +build dependencies have to to be installed at this point, +see ../qtbase/src/plugins/platforms/xcb/README + + ./configure --prefix=$YOURPREFIX \ + -opensource \ + -release -nomake tests -nomake examples -confirm-license \ + -static -no-cups -no-nis -no-icu -fontconfig \ + -no-directfb -no-opengl -no-kms -no-eglfs -no-egl -no-openssl -no-glib + nice make -j8 + make install + + cd qttools/src/linguist + qmake + nice make -j8 + make install -k + + curl -O https://polarssl.org/download/polarssl-1.3.7-gpl.tgz + 6beef0281160bf07fefefd6b412dd1ce4c39261cf5300835aef442253f0400e5 polarssl-1.3.7-gpl.tgz + + tar -xf polarssl-1.3.7-gpl.tgz + cd polarssl-1.3.7 + mkdir build + cd build + cmake .. -DCMAKE_C_FLAGS=-fpic -DCMAKE_INSTALL_PREFIX=$YOURPREFIX + make && make test && make install + +To compile the software you can use plain cmake. An out of source build is +highly suggested. For build options see CMakeList.txt + + hg clone https://wald.intevation.org/hg/trustbridge/ + cd trustbridge + mkdir build-linux + cd build-linux + cmake .. -DCMAKE_PREFIX_PATH=$YOURPREFIX + + +Hiawatha (for Downloader unit test) +=================================== +Hiawatha is used in the downloader unit tests to provide a testbench +for the ssl connection. To build it you may need libxslt-dev as additional +dependency. + + wget https://www.hiawatha-webserver.org/files/hiawatha-9.5.tar.gz + sha256sum hiawatha-9.5.tar.gz + +c181011db1af187006190fc186689a0707a6f1e7b524c2a4347840e8fdf68b4f hiawatha-9.5.tar.gz + + tar -xf hiawatha-9.5.tar.gz + cp polarssl-1.3.7-gpl.tgz hiawatha-9.5/polarssl/polarssl.tgz + cd hiawatha-9.5/polarssl + sed -i 's/wget.*//' upgrade + ./upgrade 1.3.7 + cd .. + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX=$YOURPREFIX + make && make install + +Osslsigncode (for binverify unit test) +====================================== +Osslsigncode is used to create PKCS#7 embedded signatures for Windows Authenticode +it is needed for the Windows part of the binverify unit test on the build system. + +Currently (23.06.2014) there is no released version with the OpenSSL exception +available so we need to use the git version. + + git clone git://git.code.sf.net/p/osslsigncode/osslsigncode osslsigncode + cd osslsigncode + git checkout 03848a9c60f957bf13bab39512d8fcfb4cb1fc98 + ./autogen.sh + ./configure --prefix=$YOURPREFIX + make && make install + + # for a windows binary (optional) + OPENSSL_CFLAGS=-I$MXETARGET/include OPENSSL_LIBS="-L$MXETARGET/lib -lcrypto -lz -lgdi32" ./configure --without-curl --host=i686-w64-mingw32 --prefix=$MXETARGET + +For Microsoft Windows +===================== +The Windows variant can be cross compiled on Debian based GNU / Linux systems. +The minimum requirement is Debian stable. +Tested development platform: Ubuntu 13.10. + +Dependencies on the Host system: + git autoconf automake bash bison bzip2 \ + cmake flex gettext git g++ intltool \ + libffi-dev libtool libltdl-dev libssl-dev \ + libxml-parser-perl make openssl patch perl \ + pkg-config scons sed unzip wget xz-utils autopoint \ + gperf + +Build the windows binaries: + MXEPATH=$YOURPREFIX/win + git clone https://github.com/mxe/mxe.git $MXEPATH + cd $MXEPATH + echo "MXE_TARGETS := i686-w64-mingw32.static" > settings.mk + make polarssl + make qtbase + +Workaround Qt CMake Bugs: + find $MXEPATH/usr/i686-w64-mingw32.static/qt5/lib/cmake -name \*.cmake | \ + xargs sed -i 's/\/\([a-z]*\)\.lib/\/lib\1\.a/g' + sed -i 's/^_qt5gui_find_extra_libs.*//' \ + $MXEPATH/usr/i686-w64-mingw32.static/qt5/lib/cmake/Qt5Gui/Qt5GuiConfigExtras.cmake + +Make an NSS build available in the MXE prefix: + # TODO -> Document how to build NSS,.. + cp -r $MXEPATH/usr/i686-w64-mingw32.static/ + +Compile the software: + cd trustbridge + mkdir build-windows + cd build-windows + MXETARGET=$MXEPATH/usr/i686-w64-mingw32.static/ + cmake .. \ + -DCMAKE_PREFIX_PATH="$MXETARGET/qt5;$MXETARGET;" \ + -DNSS_INCLUDEDIR="/nss-3.12.7/include;/nss-3.12.7/public/nss" \ + -DNSS_LIBDIR="/nss-3.12.7/lib" \ + -DCMAKE_TOOLCHAIN_FILE="$MXETARGET/share/cmake/mxe-conf.cmake" \ + -DCMAKE_VERBOSE_MAKEFILE=True diff -r 39f03316f675 -r 129e611eaf50 cinst/main.c --- a/cinst/main.c Wed Jun 25 14:56:19 2014 +0200 +++ b/cinst/main.c Wed Jun 25 15:16:24 2014 +0200 @@ -84,7 +84,7 @@ if (*to_install || *to_remove) { - printf ("Error invalid parameters.\n"); + ERRORPRINTF ("Error invalid parameters.\n"); return -1; } @@ -113,13 +113,13 @@ size_t len = strlen (buf); /* fgets ensures buf is terminated */ if (len <= 3) { - printf ("Line too short.\n"); + ERRORPRINTF ("Line too short.\n"); fclose (f); return ERR_INVALID_INPUT; } if (lines_read++ > MAX_LINES) { - printf ("Too many lines\n"); + ERRORPRINTF ("Too many lines\n"); fclose (f); return ERR_TOO_MUCH_INPUT; } diff -r 39f03316f675 -r 129e611eaf50 cinst/mozilla.c --- a/cinst/mozilla.c Wed Jun 25 14:56:19 2014 +0200 +++ b/cinst/mozilla.c Wed Jun 25 15:16:24 2014 +0200 @@ -442,13 +442,14 @@ cert = CERT_DecodeCertFromPackage((char *)dercert->data, (int)dercert->len); trust = (CERTCertTrust *)xmalloc(sizeof(CERTCertTrust)); - CERT_DecodeTrustString(trust, "C"); + CERT_DecodeTrustString(trust, "C,C,C"); if ((PK11_ImportCert(pk11slot, cert, CK_INVALID_HANDLE, cert_name, PR_FALSE) == SECSuccess) && (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, trust) == SECSuccess)) { + log_certificate_der (pdir, dercert->data, dercert->len, true); success = true; } else @@ -491,6 +492,7 @@ if (SEC_DeletePermCertificate(cert) == SECSuccess) { success = true; + log_certificate_der (pdir, dercert->data, dercert->len, false); } else { @@ -524,7 +526,7 @@ * formatted certificate. The function must return true on success * and false on failure. * - * This function is intended wor use with the import_cert and + * This function is intended for use with the import_cert and * remove_cert functions. * * @param[in] fn the function to apply diff -r 39f03316f675 -r 129e611eaf50 cinst/nssstore_linux.c --- a/cinst/nssstore_linux.c Wed Jun 25 14:56:19 2014 +0200 +++ b/cinst/nssstore_linux.c Wed Jun 25 15:16:24 2014 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include #include "nssstore.h" #include "logging.h" @@ -158,15 +159,15 @@ if (pid == (pid_t) 0) { /* Drop privileges */ - if (setuid (uid) || setgid (gid)) + if (setgid (gid) || setuid (uid)) { + syslog_error_printf("Failed to drop privileges: %s", strerror(errno)); exit(-1); } close (pipe_fd[1]); dup2 (pipe_fd[0], 0); close (pipe_fd[0]); - /* TODO find path based on current executable */ execve (argv[0], argv, envp); exit (127); } @@ -238,7 +239,8 @@ int write_stores_nss (char **to_install, char **to_remove) { - uid_t my_uid = getuid(); + struct passwd *usr_it = NULL; + uid_t my_uid = geteuid(); if (my_uid != 0) { @@ -269,8 +271,32 @@ return 0; } - printf ("Installation as root is not yet implemented\n"); - /* TODO root parse /etc/passwd for users with a home directory */ + + setpwent(); + + while ((usr_it = getpwent ()) != NULL) + { + /* Skip obvious system accounts */ + if (strcmp(usr_it->pw_shell, "/usr/sbin/nologin") == 0 || + strcmp(usr_it->pw_shell, "/bin/false") == 0) + { + continue; + } + /* A check if the home directory starts with /home might be + appropiate */ + start_procces_for_user (to_install, + to_remove, + usr_it->pw_uid, + usr_it->pw_gid, + usr_it->pw_dir); + + } + + endpwent(); + + waitpid (-1, NULL, 0); + + DEBUGPRINTF ("NSS installation done\n"); return 0; } #endif diff -r 39f03316f675 -r 129e611eaf50 cinst/windowsstore.c --- a/cinst/windowsstore.c Wed Jun 25 14:56:19 2014 +0200 +++ b/cinst/windowsstore.c Wed Jun 25 15:16:24 2014 +0200 @@ -28,7 +28,7 @@ if (ret != 0) { - printf ("decoding certificate failed\n"); + ERRORPRINTF ("decoding certificate failed\n"); return NULL; } @@ -45,7 +45,7 @@ char *error = getLastErrorMsg(); if (error) { - printf ("Failed to create cert context: %s \n", error); + ERRORPRINTF ("Failed to create cert context: %s \n", error); free (error); } return NULL; @@ -58,6 +58,7 @@ { PCCERT_CONTEXT pCert = NULL; unsigned int i = 0; + bool elevated = is_elevated(); if (!to_remove) { @@ -76,7 +77,7 @@ char *error = getLastErrorMsg(); if (error) { - printf ("Failed to create cert context: %s \n", error); + ERRORPRINTF ("Failed to create cert context: %s \n", error); free (error); } continue; @@ -93,7 +94,7 @@ if (pCert == NULL) { - printf ("Did not find certificate\n"); + ERRORPRINTF ("Did not find certificate\n"); continue; } @@ -104,10 +105,12 @@ pCertContext by calling the CertFreeCertificateContext function, even if an error is encountered. */ char *error = getLastErrorMsg(); - printf ("Error deleting certificate. %s", error); + ERRORPRINTF ("Error deleting certificate. %s", error); free (error); continue; } + log_certificate (elevated ? "Local Machine" : "Current User", + to_remove[i], false); } return; } @@ -117,6 +120,7 @@ { int i = 0, ret = -1; + bool elevated = is_elevated(); if (!to_install) { @@ -144,7 +148,7 @@ NULL); if (found_cert != NULL) { - printf ("Certificate already in store\n"); + DEBUGPRINTF ("Certificate already in store\n"); CertFreeCertificateContext (found_cert); CertFreeCertificateContext (pc_to_add); continue; @@ -160,10 +164,12 @@ char *error = getLastErrorMsg(); if (error) { - printf ("Failed to add certificate: %s \n", error); + ERRORPRINTF ("Failed to add certificate: %s \n", error); free (error); } } + log_certificate (elevated ? "Local Machine" : "Current User", + to_install[i], true); } return; } diff -r 39f03316f675 -r 129e611eaf50 common/CMakeLists.txt --- a/common/CMakeLists.txt Wed Jun 25 14:56:19 2014 +0200 +++ b/common/CMakeLists.txt Wed Jun 25 15:16:24 2014 +0200 @@ -5,6 +5,8 @@ # and comes with ABSOLUTELY NO WARRANTY! # See LICENSE.txt for details. +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set (trustbridge_common_src certhelp.c listutil.c @@ -12,6 +14,27 @@ portpath.c strhelp.c util.c + binverify.c + selftest.c ) +if(WIN32) + # Add the event messages + if (MINGW) + STRING(REGEX REPLACE "windres" "windmc" MC_COMPILER ${CMAKE_RC_COMPILER}) + else() + # untested + set(MC_COMPILER "mc.exe") + endif() + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/events.h + ${CMAKE_CURRENT_BINARY_DIR}/events.rc + ${CMAKE_CURRENT_BINARY_DIR}/MSG00407.bin + ${CMAKE_CURRENT_BINARY_DIR}/MSG00409.bin + COMMAND ${MC_COMPILER} ${CMAKE_SOURCE_DIR}/common/events.mc -a -U -r ${CMAKE_CURRENT_BINARY_DIR} -h ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/events.mc) + set(trustbridge_common_src ${trustbridge_common_src} ${CMAKE_CURRENT_BINARY_DIR}/events.h) +endif() + add_library(trustbridge_common STATIC ${trustbridge_common_src}) diff -r 39f03316f675 -r 129e611eaf50 common/binverify.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/binverify.c Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,227 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#include "binverify.h" + +#include "strhelp.h" +#include "logging.h" + +#ifdef RELEASE_BUILD +#include "pubkey-release.h" +#else +#include "pubkey-test.h" +#endif + +bin_verify_result +verify_binary(const char *filename, size_t name_len) { +#ifdef WIN32 + return verify_binary_win(filename, name_len); +#else + /* TODO */ + if (filename && name_len) + return VerifyValid; + return VerifyUnknownError; +#endif +} + +#ifdef WIN32 + +#include + +#include +#include +#include +#include + + +/** @brief Check if the certificate @a pCCertContext is pinned + * + * Compares the certificate's binary data (public key and attributes) + * with each other to validate that the certificate pCCertContext has + * exactly the same data as the builtin public certificate. + * + * @param[in] pCCertContext pointer to the certificate to check + * + * @returns true if the certificate matches, false otherwise. + */ +static bool +check_certificate (PCCERT_CONTEXT pCCertContext) +{ + x509_crt codesign_cert; + int ret = 0; + DWORD dwI = 0; + bool retval = false; + + if (pCCertContext == NULL) + { + ERRORPRINTF ("Invalid call to check_certificate"); + return false; + } + + x509_crt_init(&codesign_cert); + + /* Parse the pinned certificate */ + ret = x509_crt_parse(&codesign_cert, + public_key_codesign_pem, + public_key_codesign_pem_size); + if (ret != 0) + { + ERRORPRINTF ("x509_crt_parse failed with -0x%04x\n\n", -ret); + goto done; + } + + if (codesign_cert.raw.len != pCCertContext->cbCertEncoded || + codesign_cert.raw.len <= 0) + { + ERRORPRINTF ("Certificate size mismatch"); + goto done; + } + + /* Check that the certificate is exactly the same as the pinned one */ + for (dwI = 0; dwI < pCCertContext->cbCertEncoded; dwI++) + { + if (pCCertContext->pbCertEncoded[dwI] != codesign_cert.raw.p[dwI]) + { + ERRORPRINTF ("Certificate content mismatch"); + goto done; + } + } + + retval = true; + +done: + x509_crt_free(&codesign_cert); + return retval; +} + +bin_verify_result +verify_binary_win(const char *filename, size_t name_len) { + bin_verify_result retval = VerifyUnknownError; + WCHAR *filenameW = NULL; + BOOL result = FALSE; + DWORD dwEncoding = 0, + dwContentType = 0, + dwFormatType = 0, + dwSignerInfoSize = 0; + HCERTSTORE hStore = NULL; + HCRYPTMSG hMsg = NULL; + PCERT_INFO pSignerCert = NULL; + PCCERT_CONTEXT pSignerCertContext = NULL; + + if (!filename || name_len > MAX_PATH || strlen(filename) != name_len) + { + ERRORPRINTF ("Invalid parameters\n"); + return VerifyUnknownError; + } + + filenameW = utf8_to_wchar(filename, name_len); + + result = CryptQueryObject (CERT_QUERY_OBJECT_FILE, + filenameW, + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, + CERT_QUERY_FORMAT_FLAG_BINARY, + 0, + &dwEncoding, + &dwContentType, + &dwFormatType, + &hStore, + &hMsg, + NULL); + + if (!result || !hMsg) + { + PRINTLASTERROR ("Failed to query crypto object"); + retval = VerifyReadFailed; + goto done; + } + + /* Get the cert info so that we can look up the signer in the store later */ + if (CryptMsgGetParam(hMsg, + CMSG_SIGNER_CERT_INFO_PARAM, + 0, + NULL, + &dwSignerInfoSize) && dwSignerInfoSize > 0) + { + pSignerCert = xmalloc (dwSignerInfoSize); + } + else + { + ERRORPRINTF ("Failed to get signer cert size."); + retval = VerifyUnknownError; + goto done; + } + + if (!(CryptMsgGetParam(hMsg, + CMSG_SIGNER_CERT_INFO_PARAM, + 0, + pSignerCert, + &dwSignerInfoSize))) + { + ERRORPRINTF ("Failed to get signer cert."); + retval = VerifyUnknownError; + goto done; + } + + pSignerCertContext = CertGetSubjectCertificateFromStore( + hStore, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + pSignerCert); + + if (!pSignerCertContext) + { + ERRORPRINTF ("Failed to find signer cert in store."); + retval = VerifyUnknownError; + goto done; + } + + /* Verify that the signature is actually valid */ + if(!CryptMsgControl(hMsg, + 0, + CMSG_CTRL_VERIFY_SIGNATURE, + pSignerCertContext->pCertInfo)) + { + ERRORPRINTF ("The signature is invalid. \n"); + retval = VerifyInvalidSignature; + syslog_error_printf ("Software update embedded signature is invalid."); + goto done; + } + + if(check_certificate(pSignerCertContext)) + { + DEBUGPRINTF ("Valid signature with pinned certificate."); + retval = VerifyValid; + goto done; + } + else + { + ERRORPRINTF ("Certificate mismatch. \n"); + retval = VerifyInvalidCertificate; + syslog_error_printf ("Software update embedded signature " + "created with wrong certificate."); + goto done; + } + +done: + xfree(filenameW); + xfree(pSignerCert); + + if(pSignerCertContext) + { + CertFreeCertificateContext(pSignerCertContext); + } + if (hStore) + { + CertCloseStore(hStore, 0); + } + if (hMsg) + { + CryptMsgClose(hMsg); + } + return retval; +} +#endif /* WIN32 */ diff -r 39f03316f675 -r 129e611eaf50 common/binverify.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/binverify.h Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,64 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +#ifndef BINVERIFY_H +#define BINVERIFY_H +/* @file binverify.h + * @brief Verification of binary files + */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @enum bin_verify_result + * @brief Result of a verification + */ +typedef enum { + VerifyValid = 100, /*! Could be read and signature matched */ + VerifyUnknownError = 1, /*! The expected unexpected */ + VerifyInvalidSignature = 4, /*! Signature was invalid */ + VerifyInvalidCertificate = 5, /*! Certificate mismatch */ + VerifyReadFailed = 6, /*! File exists but could not read the file */ +} bin_verify_result; + +/** + * @brief verify a binary + * + * This function checks that a binary is signed by a built + * in certificate. + * + * Caution: This function works on file names only which could + * be modified after this check. + * + * The verification is done using Windows crypto API based on + * embedded PKCS 7 "authenticode" signatures embedded into the + * file. + * + * @param[in] filename absolute null terminated UTF-8 encoded path to the file. + * @param[in] name_len length of the filename. + * + * @returns the verification result. + */ +bin_verify_result verify_binary(const char *filename, size_t name_len); + +#ifdef WIN32 +/** + * @brief windows implementation of verify_binary + */ +bin_verify_result verify_binary_win(const char *filename, size_t name_len); +#endif /* WIN32 */ + +#ifdef __cplusplus +} +#endif + +#endif /* BINVERIFY_H */ diff -r 39f03316f675 -r 129e611eaf50 common/events.mc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/events.mc Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,109 @@ +; /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik +; Software engineering by Intevation GmbH +; +; This file is Free Software under the GNU GPL (v>=2) +; and comes with ABSOLUTELY NO WARRANTY! +; See LICENSE.txt for details. */ + + +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS +Informational=0x1:STATUS_SEVERITY_INFORMATIONAL +Warning=0x2:STATUS_SEVERITY_WARNING +Error=0x3:STATUS_SEVERITY_ERROR +) + +FacilityNames=(System=0x0:FACILITY_SYSTEM + Runtime=0x2:FACILITY_RUNTIME + Stubs=0x3:FACILITY_STUBS + Io=0x4:FACILITY_IO_ERROR_CODE + ) + +LanguageNames=(English=0x409:MSG00409) +LanguageNames=(German=0x407:MSG00407) + +MessageIdTypedef=WORD + +MessageId=0x1 +SymbolicName=EVENT_CAT_TB +Language=English +Trustbridge +. +Language=German +Trustbridge +. + +MessageId=0x2 +SymbolicName=EVENT_CAT_CINST +Language=English +Certificate Installer +. +Language=German +Zertifikatsinstaller +. + + +MessageId=0x3 +SymbolicName=EVENT_CAT_NSS +Language=English +NSS +. +Language=German +NSS +. +;/* THE MESSAGES */ + +MessageIdTypedef=DWORD + +MessageId=0x100 +Severity=Informational +Facility=Runtime +SymbolicName=MSG_DEFAULT_INFO +Language=English +%1 +. +Language=German +%1 +. + +MessageId=0x101 +Severity=Error +Facility=Runtime +SymbolicName=MSG_DEFAULT_ERROR +Language=English +%1 +. +Language=German +%1 +. + +;/* Keep the following two lines in line with the linux counterparts in +; logging.c */ +MessageId=0x102 +Severity=Informational +Facility=Runtime +SymbolicName=MSG_CERT_INSTALL +Language=English +Installation of root certificate: %1%n +Sha256 thumbprint:<%2>%n +Certificate store: "%3" +. +Language=German +Installation des Wurzelzertifikats: %1%n +Sha256 Fingerabdruck:<%2>%n +Zertifikatsspeicher: "%3" +. + +MessageId=0x103 +Severity=Informational +Facility=Runtime +SymbolicName=MSG_CERT_REMOVE +Language=English +Removal of root certificate: %1%n +Sha256 thumbprint:<%2>%n +Certificate store: "%3" +. +Language=German +Entfernung des Wurzelzertifikats: %1%n +Sha256 Fingerabdruck:<%2>%n +Zertifikatsspeicher: "%3" +. diff -r 39f03316f675 -r 129e611eaf50 common/listutil.c --- a/common/listutil.c Wed Jun 25 14:56:19 2014 +0200 +++ b/common/listutil.c Wed Jun 25 15:16:24 2014 +0200 @@ -17,6 +17,7 @@ #include #include "strhelp.h" +#include "logging.h" #ifdef RELEASE_BUILD #include "pubkey-release.h" @@ -168,7 +169,7 @@ ret = pk_parse_public_key(&pub_key_ctx, public_key_pem, public_key_pem_size); if (ret != 0) { - printf("pk_parse_public_key failed with -0x%04x\n\n", -ret); + ERRORPRINTF ("pk_parse_public_key failed with -0x%04x\n\n", -ret); pk_free(&pub_key_ctx); return ret; } @@ -177,7 +178,7 @@ signature, sig_size); if (ret != 0) { - printf("pk_verify failed with -0x%04x\n\n", -ret); + ERRORPRINTF ("pk_verify failed with -0x%04x\n\n", -ret); } pk_free(&pub_key_ctx); @@ -249,7 +250,7 @@ if (!data || !size) { - printf ("Invalid call to get_certs_to_remove \n"); + ERRORPRINTF ("Invalid call to get_certs_to_remove \n"); return NULL; } diff -r 39f03316f675 -r 129e611eaf50 common/listutil.h --- a/common/listutil.h Wed Jun 25 14:56:19 2014 +0200 +++ b/common/listutil.h Wed Jun 25 15:16:24 2014 +0200 @@ -23,15 +23,15 @@ * @brief Status of the List Operations */ typedef enum { - Valid = 100, // Could be read and signature matched - UnknownError = 1, // The expected unexpected - TooLarge = 2, // Failed because the file exeeds the limit - InvalidFormat = 3, // File does not appear to be in list format - InvalidSignature = 4, // Signature was invalid - SeekFailed = 5, // Could not seek in the file - ReadFailed = 6, // File exists but could not read the file - IncompatibleVersion = 7, // The Format Version does not match - NoList = 8 // No list parsed + Valid = 100, /*! Could be read and signature matched */ + UnknownError = 1, /*! The expected unexpected */ + TooLarge = 2, /*! Failed because the file exeeds the limit */ + InvalidFormat = 3, /*! File does not appear to be in list format */ + InvalidSignature = 4, /*! Signature was invalid */ + SeekFailed = 5, /*! Could not seek in the file */ + ReadFailed = 6, /*! File exists but could not read the file */ + IncompatibleVersion = 7, /*! The Format Version does not match */ + NoList = 8 /*! No list parsed */ } list_status_t; /* Definitions based on the format */ diff -r 39f03316f675 -r 129e611eaf50 common/logging.c --- a/common/logging.c Wed Jun 25 14:56:19 2014 +0200 +++ b/common/logging.c Wed Jun 25 15:16:24 2014 +0200 @@ -9,8 +9,112 @@ #include "strhelp.h" #include +#include +#include + +#include + +#include + +#include #ifdef WIN32 +# include +# include "events.h" +#else +# include +#endif + +#ifdef WIN32 + +/** @brief helper to prepare common logging information */ +static void +win_do_log(WORD type, WORD category, DWORD eventID, WORD numStrings, LPCWSTR *strings) +{ + HANDLE log_src = NULL, + process_token = NULL; + PTOKEN_USER user_struct = NULL; + PSID user_sid = NULL; + BOOL success = FALSE; + + log_src = RegisterEventSourceW (NULL, L"" LOG_NAME); + + if (log_src == NULL) + { + PRINTLASTERROR ("Failed to open log source."); + return; + } + + /* Get the current user sid for logging */ + OpenProcessToken (GetCurrentProcess(), TOKEN_READ, &process_token); + if (process_token) + { + DWORD size = 0; + + // check how much space is needed + GetTokenInformation (process_token, TokenUser, NULL, 0, &size); + if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) + { + user_struct = xmalloc (size); + GetTokenInformation (process_token, TokenUser, user_struct, size, &size); + user_sid = user_struct->User.Sid; + } + } + + success = ReportEventW (log_src, + type, + category, + eventID, + user_sid, + numStrings, + 0, + strings, + NULL); + if (!success) + { + PRINTLASTERROR ("Failed to report event."); + } + + if (process_token) + { + CloseHandle(process_token); + } + xfree (user_struct); + + if (!DeregisterEventSource (log_src)) + { + PRINTLASTERROR ("Failed to close log source."); + } +} + +static void +win_log(const char *format, va_list ap, bool error) +{ + wchar_t *wmsg = NULL; + char buffer[MAX_LOG+1]; + vsnprintf (buffer, MAX_LOG, format, ap); + + buffer[MAX_LOG] = '\0'; + + wmsg = utf8_to_wchar (buffer, strlen(buffer)); + if (wmsg == NULL) + { + ERRORPRINTF ("Failed to convert log message to utf-16"); + return; + } + + win_do_log (error ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, + EVENT_CAT_TB, + error ? MSG_DEFAULT_ERROR : MSG_DEFAULT_INFO, + 1, + (const WCHAR **) &wmsg); + + + xfree (wmsg); + + return; +} + char * getLastErrorMsg() { @@ -44,4 +148,122 @@ return retval; } +#else /* WIN32 */ + +static void +linux_log (const char *format, va_list ap, bool error) +{ + openlog (LOG_NAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER); + vsyslog ( error ? LOG_ERR : LOG_INFO, format, ap); +} + +#endif /* WIN32 */ + +void +log_certificate(const char* store, char *b64cert, bool install) +{ + char *der_data = NULL; + size_t der_size = 0; + int ret = 0; + + ret = str_base64_decode (&der_data, &der_size, b64cert, strlen(b64cert)); + + if (ret != 0) + { + ERRORPRINTF ("Error decoding certificate.\n"); + return; + } + + log_certificate_der (store, (unsigned char *) der_data, der_size, install); + + xfree (der_data); +} + +void +log_certificate_der(const char *store, unsigned char *der_data, size_t der_size, bool install) +{ + char subject[MAX_LOG + 1]; + int ret = 0, + i = 0; + x509_crt chain; + unsigned char sha256sum[32]; + char fingerprint[32 * 3 + 1]; + + x509_crt_init(&chain); + if (x509_crt_parse_der(&chain, (const unsigned char *)der_data, + der_size) != 0) + { + ERRORPRINTF("Failed to parse cert.."); + return; + } + + ret = x509_dn_gets(subject, MAX_LOG, &(chain.subject)); + + if (ret == -1) + { + ERRORPRINTF("Failed to parse subject.."); + return; + } + subject[MAX_LOG] = '\0'; + + sha256 (chain.raw.p, chain.raw.len, sha256sum, 0); + + for (i = 0; i < 31; i++) + { + snprintf (fingerprint + (i * 3), 4, "%02X:", sha256sum[i]); + } + snprintf (fingerprint + (31 * 3), 3, "%02X", sha256sum[31]); + + fingerprint[32*3] = '\0'; + +#ifdef WIN32 + { + wchar_t *wstrings[3]; + + wstrings[0] = utf8_to_wchar (subject, strnlen (subject, MAX_LOG)); + wstrings[1] = utf8_to_wchar (fingerprint, strnlen (fingerprint, MAX_LOG)); + wstrings[2] = utf8_to_wchar (store, strnlen (store, MAX_LOG)); + + win_do_log (EVENTLOG_INFORMATION_TYPE, + EVENT_CAT_CINST, + install ? MSG_CERT_INSTALL : MSG_CERT_REMOVE, + 3, + (const WCHAR**) wstrings); + xfree (wstrings[0]); + xfree (wstrings[1]); + xfree (wstrings[2]); + } +#else + /* Please keep the following line in line with message from events.mc */ + syslog_info_printf ("%s of root certificate: %s Sha256 thumbprint:<%s>. Certificate store \"%s\"", + install ? "Installation" : "Removal", + subject, fingerprint, store); #endif + x509_crt_free (&chain); +} + +void +syslog_info_printf(const char *format, ...) +{ + va_list args; + va_start (args, format); +#ifdef WIN32 + win_log (format, args, false); +#else + linux_log (format, args, false); +#endif + va_end (args); +} + +void +syslog_error_printf(const char *format, ...) +{ + va_list args; + va_start (args, format); +#ifdef WIN32 + win_log (format, args, true); +#else + linux_log (format, args, true); +#endif + va_end (args); +} diff -r 39f03316f675 -r 129e611eaf50 common/logging.h --- a/common/logging.h Wed Jun 25 14:56:19 2014 +0200 +++ b/common/logging.h Wed Jun 25 15:16:24 2014 +0200 @@ -18,6 +18,13 @@ */ #include +#include + +/** @def Maximum length of log messages */ +#define MAX_LOG 511 + +/** @def The name used for logging */ +#define LOG_NAME "TrustBridge" #ifdef WIN32 @@ -108,6 +115,51 @@ ERRORPRINTF ("Failed to get error information\n"); +/** + * @brief log an informational message into the syslog / event log + * + * The message length is limited to MAX_LOG characters. Log messages + * are expected to be in UTF-8 encoding. + * + * Function paramters are the same as for the printf familiy. + */ +void syslog_info_printf(const char *format, ...); + +/** + * @brief log an error message into the syslog / event log + * + * The message length is limited to MAX_LOG characters. Log messages + * are expected to be in UTF-8 encoding. + * + * Function paramters are the same as for the printf familiy. + */ +void syslog_error_printf(const char *format, ...); + + /** + * @brief log a certificate install / remove event from base64 data. + * + * Logs a message in the event / syslog to mark a certificate + * installation or removal. + * + * @param[in] store name of the certificate store. + * @param[in] b64cert base64 encoded certificate. + * @param[in] install weather to log this as installation or removal + */ +void log_certificate(const char *store, char *b64cert, bool install); + +/** + * @brief log a certificate install / remove event from der data. + * + * Logs a message in the event / syslog to mark a certificate + * installation or removal. + * + * @param[in] store name of the certificate store. + * @param[in] der_data pointer to der data of the certificate. + * @param[in] der_size size of the der_data + * @param[in] install weather to log this as installation or removal + */ +void log_certificate_der(const char *store, unsigned char *der_data, size_t der_size, bool install); + #ifdef __cplusplus } #endif diff -r 39f03316f675 -r 129e611eaf50 common/pubkey-test.h --- a/common/pubkey-test.h Wed Jun 25 14:56:19 2014 +0200 +++ b/common/pubkey-test.h Wed Jun 25 15:16:24 2014 +0200 @@ -23,4 +23,43 @@ "-----END PUBLIC KEY-----\n"; static const size_t public_key_pem_size = 625; + +/* Key used for codesigning */ +static const unsigned char public_key_codesign_pem[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIFqTCCA5GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBZMSAwHgYDVQQDExdQdWJs\n" +"aWMgVHJ1c3RCcmlkZ2UgVGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBu\n" +"b3QgdHJ1c3QgdGhpczELMAkGA1UEBhMCREUwHhcNMTMwMTAxMDAwMDAwWhcNMTUx\n" +"MjMxMjM1OTU5WjBlMSwwKgYDVQQDEyNQdWJsaWMgVHJ1c3RCcmlkZ2UgY29kZXNp\n" +"Z25pbmcgdGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBub3QgdHJ1c3Qg\n" +"dGhpczELMAkGA1UEBhMCREUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" +"AQDIz9IetAtdqJJ7aSfJcLmA9Mb4nxrqEJ5E6PMejDJZmmHNjyhCVp1qsLYmyC60\n" +"m7qJ4OBENx0v2n5LiCUHJpJ4mzAklkWn1GffUkzWgQ2VHw5Nr44NWEwkUUa5/jT7\n" +"Sxts2DWuaLz2r7oi6BUQpoRmQRPwwzFPONcCSw9iAvTU6oVI2jW1opEW3t10UwY3\n" +"5/muryPsUz6y5VkBIc73VC0wByXoAruEPBBpMgOVw1+npOaJ1PL1XXQ/P6xziZo0\n" +"Ab/tKvN6IpEHrNEGv1gScJt//pKKklvIyXm9UdIY9XpB6aauzthKpTFJXGYySlXx\n" +"bD1a5sq0i2sAK/p8RvErVWg3EfBlUrQryJxONPVqribczZIWcgKVEFfXjX1tQqiC\n" +"qRCgO4M6zhNIKLkAicp0DvYs8M4hIoPng98nqK6kSpfXR6Y4b9DU3yEktH7wGrwL\n" +"jKATVM2l2yTF17Pjxkr2tH0XWrChfS+oV6Qzm9JQ/vmLKz5piLKpt5SXuZny+j0Y\n" +"68ch709sVTuuPm4RAm5c5t0SCwEippClFpkZynYRsJVrjG9ZTrdvULxZao8GBzJx\n" +"Lb+tCaKP60BRoUuRfwGMKZbU6j6ujOCy5bZIoJaKgHgyAHXRuS4PIjY9K2BGM5vI\n" +"seA2GEdAJNmZPAQJE5rxkrsAH9n8QtmHucEqzCZVFcLuCwIDAQABo3AwbjAJBgNV\n" +"HRMEAjAAMB0GA1UdDgQWBBSMgUaKY3L65wH5M4il/gbHCeVm4TAfBgNVHSMEGDAW\n" +"gBTl/kZGRoa0cm82zW7CPn3yqk4MeTAOBgNVHQ8BAQEEBAMCAYAwEQYJYIZIAYb4\n" +"QgEBBAQDAgAQMA0GCSqGSIb3DQEBBQUAA4ICAQAdmpf8k+ZKuhDvNwMCrf1JIZh3\n" +"uJxlCHFke/ypsMT2E6p/GZpD/lLyRHbk7V5aEYdmBaK6Dem0KYhRuDclWscpQdXl\n" +"96wx1IDNueMkj5ZDmpBLFl/nqxlM9HfHo8YTE9dRgzJAR8+dFR8HyRSayKo+pz4L\n" +"FkNFT5Jtm9kKLIN+mSGKMBmpY4owfpeh7K6YyASoOHL9Zk8A0I7iZX8FB5KujrlG\n" +"WJahjSAyvLvy98XDCf9/SyX73F1ol5ycAb/du+G5VZFDEI8sv/7fIdTx/AUR30Ac\n" +"f3tqXZ4HwxWc0gofT0J2z/I4FZ/sT/1SNHReGNrG9GNn5bxjwpSXfc5A1bjhRfxd\n" +"x73xKEInjpgo6AXY7wfNk1V+2z7keVOpaDEZUOsd/x/C+L8FsUh2JJHZp/hKX6Co\n" +"AD///pxqNfvH5pPLUINC7VRUOTynUas7p9UvkPeJjqnWY6pmjeb4Fs6Z6vn0+Opy\n" +"HP1MjLL41a+U9VxuNb6SfRDoeT19pqK6ovT2gbc61OvTI0lE97ChC622rjnV0c/N\n" +"QYqkeTQG/IjPk0QFrYQxMqq6QKgds2nheYd4LyLGhk72pKWr28Hfj1ElcoTFFbWP\n" +"ndI+uZePkkCsVYNMXbIAIpqLb++1ftl+L+itqxTyq+0tPObIL3WG9rzBGz8X6WT0\n" +"KIzi4KAn66e5/iWZng==\n" +"-----END CERTIFICATE-----\n"; + +static const size_t public_key_codesign_pem_size = 2025; + #endif diff -r 39f03316f675 -r 129e611eaf50 common/selftest.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/selftest.c Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,46 @@ +#include "selftest.h" +#include "binverify.h" +#include "strhelp.h" +#include "logging.h" + +bool +selftest() +{ +#ifdef WIN32 + wchar_t wPath[MAX_PATH]; + char *utf8path = NULL; + + if (!GetModuleFileNameW (NULL, wPath, MAX_PATH - 1)) + { + PRINTLASTERROR ("Failed to obtain module file name. Path too long?"); + return false; + } + + /* wPath might not be 0 terminated */ + wPath[MAX_PATH - 1] = '\0'; + + utf8path = wchar_to_utf8 (wPath, wcsnlen(wPath, MAX_PATH)); + + if (utf8path == NULL) + { + ERRORPRINTF ("Failed to convert module path to utf-8"); + return false; + } + + if (!verify_binary (utf8path, strlen(utf8path)) != VerifyValid) + { + ERRORPRINTF ("Verification of the binary failed"); + syslog_error_printf ("Integrity check failed."); + xfree(utf8path); + return false; + } + + xfree(utf8path); +#else + if (!verify_binary ("/proc/self/exe", 14) != VerifyValid) + { + syslog_error_printf ("Integrity check failed."); + return false; + } +#endif +} diff -r 39f03316f675 -r 129e611eaf50 common/selftest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/selftest.h Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,36 @@ +#ifndef COMMON_SELFTEST_H +#define COMMON_SELFTEST_H +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ + +/** @file self test against manipulation + * + * The selftest is intended to detect untargeted manipulation or + * corruption of the executable. Circumvention of the selftest + * by targeted manipulation of the binary can, of course, not + * be detected. + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** @brief check that the current process is signed by the correct certificate + * + * Checks that the certificate is signed with a valid signature and the + * builtin public certificate. + * + * @returns true if the selftest is successful. false on error. + */ +bool selftest(); + +#ifdef __cplusplus +} +#endif +#endif // COMMON_SELFTEST_H diff -r 39f03316f675 -r 129e611eaf50 common/util.c --- a/common/util.c Wed Jun 25 14:56:19 2014 +0200 +++ b/common/util.c Wed Jun 25 15:16:24 2014 +0200 @@ -7,10 +7,14 @@ */ #include "util.h" #include "logging.h" +#include "strhelp.h" #ifndef _WIN32 #include #include +#include +#include +#include #else #include #endif @@ -42,7 +46,58 @@ bool is_admin() { #ifndef _WIN32 - /* TODO implement */ + struct passwd *current_user = getpwuid (geteuid()); + int ngroups = 0, + ret = 0, + i = 0; + gid_t * groups = NULL; + + if (current_user == NULL) + { + ERRORPRINTF ("Failed to obtain user information."); + return false; + } + + ret = getgrouplist (current_user->pw_name, current_user->pw_gid, NULL, + &ngroups); + + if (ret != -1 || ngroups <= 0) + { + ERRORPRINTF ("Unknown error in getgrouplist call"); + return false; + } + + groups = xmalloc (((unsigned int)ngroups) * sizeof (gid_t)); + + ret = getgrouplist (current_user->pw_name, current_user->pw_gid, groups, + &ngroups); + + if (ret != ngroups) + { + ERRORPRINTF ("Group length mismatch."); + xfree (groups); + return false; + } + + for (i = 0; i < ngroups; i++) + { + struct group *gr = getgrgid (groups[i]); + if (gr == NULL) + { + ERRORPRINTF ("Error in group enumeration"); + xfree (groups); + return false; + } + if (strcmp("sudo", gr->gr_name) == 0) + { + DEBUGPRINTF ("User is in sudo group \n"); + xfree (groups); + return true; + } + } + + DEBUGPRINTF ("User is not in sudo group"); + return false; #else bool retval = false; diff -r 39f03316f675 -r 129e611eaf50 extras/testplan/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/testplan/README.txt Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,36 @@ += Test plan for TrustBridge + +TrustBridge uses the Free Software test plan framework + [[https://wald.intevation.org/projects/intests/]] +to fill out test plans with a simple web server. +InTEsts can also produce PDF output. + +To start, fetch the current version of inTests: + +{{{ + hg clone https://hg.intevation.org/intests +}}} + + +== Completing a test plan + +# Create a working copy of original testplan.xml into the intests directory: + {{{ + cd intests + cp /path/to/testplan.xml testplan.xml + }}} +# Start web server [optional with port number]: + {{{ + python main.py testplan.xml [PORT] + }}} +# Enter test information + (date, OS, tester, version, comment) +# Run all tests of each test suite and + record the test results (yes = passed, no = failed, n/a). +# Quit web server +# Create test plan protocol as PDF: +{{{ + xsltproc --stringparam lang de xforms/xml2tex.xsl testplan.xml > tex/testplan.tex + cd tex + make testplan.pdf +}}} diff -r 39f03316f675 -r 129e611eaf50 extras/testplan/testplan.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/testplan/testplan.xml Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,108 @@ + + + + TrustBridge + + + + + + 0.1 + + + + + + + + + Verwaltungsanwendung (trustbridge-admin) starten. + + + Die Anwendung startet + + + + + + Mehrere Zertifikate hinzufügen (z.B. aus ui/tests/data) + Liste erstellen + Signaturzertifikat angeben (z.B. ui/tests/data/testkey-priv.pem) + Ausgabeverzeichnis angeben + Liste erstellen + + + Liste wurde erfolgreich im Ausgabeverzeichnis gespeichert + Liste wurde erfolgreich im Archivverzeichnis (~/.local share/BSI/trustbridge-admin/) gespeichert + + + + + + Ein Zertifikat aus der Liste entfernen + Ein weiteres Zertifikate hinzufügen (z.B. aus ui/tests/data) + Liste erstellen (Signaturzertifikat und Ausgabeverzeichnis unverändert lassen) + Liste erstellen + + + Liste wurde erfolgreich im Ausgabeverzeichnis gespeichert + Liste wurde erfolgreich im Archivverzeichnis (~/.local share/BSI/trustbridge-admin/) gespeichert + + + + + + Verwaltungsanwendung neustarten + + + Die zuletzt erstellte Zertifikatsliste wird angezeigt + + + + + + Installationspaket erstellen... + Verzeichnis des Binärpakets angeben (enthält meta.ini) + Code-Signing-Zertifikat angeben (z.B. ui/tests/data/codesign/codesigning.pem) + Ausgabeverzeichnis angeben + Installationspaket erzeugen + + + Installationspaket für Windows (NSIS-Installer) wurde im Ausgabeverzeichnis erstellt. + Installationspaket für Ubuntu wurde im Ausgabeverzeichnis erstellt. + + + + + + Verwaltungsanwendung beenden. + + + Die Anwendung schließt sich + + + + + Der TrustBridge Client Installer liegt vor. + + Nutzer besitzt Adminstratorrechte. + + NSIS-Installer ausführen (mit Vorbelegung) + + + Anwendung startet nach Installation automatisch. + Eintrag im Startmenü ist vorhanden + + + + Nutzer besitzt keine Adminstratorrechte. + + NSIS-Installer ausführen (mit Vorbelegung) + + + Anwendung startet nach Installation automatisch. + Eintrag im Startmenü ist vorhanden + + + + diff -r 39f03316f675 -r 129e611eaf50 packaging/tmp-createpackage.sh.in --- a/packaging/tmp-createpackage.sh.in Wed Jun 25 14:56:19 2014 +0200 +++ b/packaging/tmp-createpackage.sh.in Wed Jun 25 15:16:24 2014 +0200 @@ -1,4 +1,4 @@ -# Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik +# Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik # Software engineering by Intevation GmbH # # This file is Free Software under the GNU GPL (v>=2) @@ -21,7 +21,7 @@ echo $TMPDIR makensis -Dfiles_dir=$TMPDIR \ - -Dcompany="Bundesamt für Sicherheit in der Informationstechnik" \ + -Dcompany="Bundesamt für Sicherheit in der Informationstechnik" \ -Dversion_number=@PROJECT_VERSION@ \ -Dsetupname="@CMAKE_BINARY_DIR@/TrustBridge-@PROJECT_VERSION@.exe" \ -Dproductname="TrustBridge" \ diff -r 39f03316f675 -r 129e611eaf50 packaging/trustbridge.nsi --- a/packaging/trustbridge.nsi Wed Jun 25 14:56:19 2014 +0200 +++ b/packaging/trustbridge.nsi Wed Jun 25 15:16:24 2014 +0200 @@ -1,4 +1,4 @@ -; Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik +; Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik ; Software engineering by Intevation GmbH ; ; This file is Free Software under the GNU GPL (v>=2) @@ -29,6 +29,7 @@ !include "MultiUser.nsh" !include "MUI2.nsh" +!include "FileFunc.nsh" ;-------------------------------- ;Version Information (for installer file properties) @@ -66,7 +67,7 @@ !define MUI_UNICON "resources\uninstall.ico" ; MUI welcome page text -!define MUI_WELCOMEPAGE_TITLE "Willkommen bei der Installation des ${productname}" +!define MUI_WELCOMEPAGE_TITLE "Willkommen bei der Installation von ${productname}" !define MUI_WELCOMEPAGE_TEXT "Dieser Assistent wird Sie durch die Installation von \ ${productname} begleiten. $\r$\n$\r$\n\ ${productname} ist eine Anwendung um Wurzelzertifikate auf ihrem System \ @@ -88,10 +89,10 @@ !define MUI_FINISHPAGE_TEXT "${productname} wurde auf Ihrem \ Computer installliert. $\r$\n$\r$\n\ Klicken Sie auf 'Fertig stellen', um den Installations-Assistenten\ -zu schließen." -!define MUI_FINISHPAGE_RUN $INSTDIR\trustbridge.exe -!define MUI_FINISHPAGE_RUN_TEXT "Anwendung starten" -!define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser +zu schließen." +;!define MUI_FINISHPAGE_RUN $INSTDIR\trustbridge.exe +;!define MUI_FINISHPAGE_RUN_TEXT "Anwendung starten" +;!define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser !define MUI_FINISHPAGE_LINK "Mehr unter http://www.bsi.bund.de" !define MUI_FINISHPAGE_LINK_LOCATION "http://www.bsi.bund.de" @@ -112,7 +113,24 @@ ; Install Functions Function ".onInit" + Var /GLOBAL is_update + Var /GLOBAL changed_dir + ${GetParameters} $R0 + ClearErrors + ${GetOptions} $R0 /UPDATE= $is_update + +; Check if the install directory was modified on the command line + StrCmp "$INSTDIR" "$PROGRAMFILES\${productname_short}" unmodified 0 + ; It is modified. Save that value. + StrCpy $changed_dir "$INSTDIR" + +; MULITUSER_INIT overwrites directory setting from command line !insertmacro MULTIUSER_INIT + StrCpy $INSTDIR "$changed_dir" + goto initDone +unmodified: + !insertmacro MULTIUSER_INIT +initDone: FunctionEnd ; If we run elevated we do not want to run @@ -134,13 +152,22 @@ SetOutPath "$INSTDIR" !include "filelist.nsh" +;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + +; Code below is not run on updates + StrCmp $is_update '1' done + WriteRegStr SHCTX "Software\${productname_short}" "" $INSTDIR -; Set up autostart - WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Run" "TrustBridge" "$INSTDIR\trustbridge.exe --tray" + WriteRegStr SHCTX "Software\${productname_short}" "" $INSTDIR -;Create uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" +; Register logging + WriteRegStr SHCTX "System\CurrentControlSet\services\eventlog\Application\${productname_short}" "CategoryMessageFile" "$INSTDIR\trustbridge.exe" + WriteRegStr SHCTX "System\CurrentControlSet\services\eventlog\Application\${productname_short}" "EventMessageFile" "$INSTDIR\trustbridge.exe" + WriteRegStr SHCTX "System\CurrentControlSet\services\eventlog\Application\${productname_short}" "ParameterMessageFile" "$INSTDIR\trustbridge.exe" + WriteRegDword SHCTX "System\CurrentControlSet\services\eventlog\Application\${productname_short}" "TypesSupported" 5 + WriteRegDword SHCTX "System\CurrentControlSet\services\eventlog\Application\${productname_short}" "CategoryCount" 3 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application @@ -149,6 +176,7 @@ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\${productname}.lnk" "$INSTDIR\trustbridge.exe" !insertmacro MUI_STARTMENU_WRITE_END +done: SectionEnd diff -r 39f03316f675 -r 129e611eaf50 ui/CMakeLists.txt --- a/ui/CMakeLists.txt Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/CMakeLists.txt Wed Jun 25 15:16:24 2014 +0200 @@ -7,7 +7,8 @@ include_directories(${Qt5Widgets_INCLUDE_DIRS}) include_directories(${POLARSSL_INCLUDE_DIR}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../common) +include_directories(${CMAKE_SOURCE_DIR}/common) +include_directories(${CMAKE_BINARY_DIR}/common) add_definitions(${Qt5Widgets_DEFINITIONS}) find_package(Qt5LinguistTools) @@ -36,13 +37,15 @@ ${CMAKE_CURRENT_SOURCE_DIR}/certificateitemwidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/separatoritemdelegate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/installwrapper.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/img/icon.rc ${CMAKE_CURRENT_SOURCE_DIR}/aboutdialog.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processhelp_win.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processhelp_linux.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processwaitdialog.cpp ${CERTIFICATELIST_SOURCES} ${DOWNLOADER_SOURCES} ) -set(ADMINSTRATOR_SOURCES +set(ADMINISTRATOR_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/administratorwindow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/certificatetablemodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/certificatetabledelegate.cpp @@ -59,7 +62,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/certs.qrc ) -set(ADMINSTRATOR_RESOURCES +set(ADMINISTRATOR_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/icons.qrc ) @@ -97,6 +100,8 @@ -ladvapi32 -lshell32 -luser32 -lkernel32 -lz -lsicuin -lsicuuc -lsicudt -lpcre16) set(EXTRA_STATIC_LIBS Qt5::QWindowsIntegrationPlugin ${WINDOWS_EXTRA_LIBS} -lwinhttp -lcrypt32) + + add_definitions(-DUNICODE) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") @@ -106,16 +111,34 @@ # Adding resources here in an extra variable to enable reuse of # TRUSTBRIDGE_SOURCES in the test subdirectory. -set(TRUSTBRIDGE_MAIN_WITH_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(TRUSTBRIDGE_MAIN_WITH_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/img/icon.rc) qt5_add_resources(TRUSTBRIDGE_MAIN_WITH_RESOURCES ${TRUSTBRIDGE_RESOURCES}) -set(ADMINSTRATOR_MAIN_WITH_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/administrator.cpp) -qt5_add_resources(ADMINSTRATOR_MAIN_WITH_RESOURCES ${ADMINSTRATOR_RESOURCES}) +set(ADMINISTRATOR_MAIN_WITH_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/administrator.cpp) +qt5_add_resources(ADMINISTRATOR_MAIN_WITH_RESOURCES ${ADMINISTRATOR_RESOURCES}) if(WIN32) # This option causes cmake to use the appropiate liker flags to hide # the console Window on Windows set (_add_executable_params WIN32) + + # Add the event messages + if (MINGW) + STRING(REGEX REPLACE "windres" "windmc" MC_COMPILER ${CMAKE_RC_COMPILER}) + else() + # untested + set(MC_COMPILER "mc.exe") + endif() + + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/common/events.h + ${CMAKE_BINARY_DIR}/common/events.rc + ${CMAKE_BINARY_DIR}/common/MSG00407.bin + ${CMAKE_BINARY_DIR}/common/MSG00409.bin + COMMAND ${MC_COMPILER} ${CMAKE_SOURCE_DIR}/common/events.mc -r ${CMAKE_BINARY_DIR}/common -h ${CMAKE_BINARY_DIR}/common + DEPENDS ${CMAKE_SOURCE_DIR}/common/events.mc) + set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/img/icon.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_BINARY_DIR}/common/events.rc) endif() if(Qt5LinguistTools_FOUND) @@ -125,11 +148,11 @@ # This would probably be better placed in a macro configure_file(l10n/administrator.qrc.in administrator.qrc) qt5_add_resources(ADMINISTRATOR_L10N ${CMAKE_CURRENT_BINARY_DIR}/administrator.qrc) - qt5_create_translation(ADMINISTRATOR_TRANSLATION ${ADMINSTRATOR_SOURCES} + qt5_create_translation(ADMINISTRATOR_TRANSLATION ${ADMINISTRATOR_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/l10n/administrator_de_DE.ts) add_executable(trustbridge-admin ${_add_executable_params} - ${ADMINSTRATOR_MAIN_WITH_RESOURCES} + ${ADMINISTRATOR_MAIN_WITH_RESOURCES} ${ADMINISTRATOR_L10N} ${ADMINISTRATOR_TRANSLATION} ) @@ -149,14 +172,14 @@ message (STATUS "WARNING: Could not find qt linguist tools. Translation will not be included.") add_executable(trustbridge-admin ${_add_executable_params} - ${ADMINSTRATOR_MAIN_WITH_RESOURCES}) + ${ADMINISTRATOR_MAIN_WITH_RESOURCES}) add_executable(trustbridge ${_add_executable_params} ${TRUSTBRIDGE_MAIN_WITH_RESOURCES}) endif() add_library(ui_common STATIC ${UICOMMON_SOURCES}) -add_library(tbadminlib STATIC ${ADMINSTRATOR_SOURCES}) +add_library(tbadminlib STATIC ${ADMINISTRATOR_SOURCES}) add_library(tblib STATIC ${TRUSTBRIDGE_SOURCES}) target_link_libraries(trustbridge-admin diff -r 39f03316f675 -r 129e611eaf50 ui/aboutdialog.h --- a/ui/aboutdialog.h Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/aboutdialog.h Wed Jun 25 15:16:24 2014 +0200 @@ -17,6 +17,7 @@ class AboutDialog : public QDialog { + Q_OBJECT public: /** @brief Create a help dialog */ AboutDialog(QMainWindow *parent); diff -r 39f03316f675 -r 129e611eaf50 ui/administratorwindow.cpp --- a/ui/administratorwindow.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/administratorwindow.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -231,6 +231,8 @@ QFile logFile(logFilePath); if (!logFile.open(QIODevice::Append)) { + QMessageBox::warning(this, tr("Error!"), tr("Failed to open log file: ") + + logFilePath + tr(" Changes are not logged!")); qDebug() << "Failed to open log file: " << logFilePath; return; } @@ -239,7 +241,8 @@ newCertList.readList(currentCerts.toLocal8Bit()); QByteArray entries = createLogEntries(newCertList); if(logFile.write(entries) != entries.size()) { - qDebug() << "Failed to write log file: " << logFilePath; + QMessageBox::warning(this, tr("Error!"), tr("Failed to write log file: ") + + logFilePath + tr(" Changes are not logged!")); return; } logFile.close(); diff -r 39f03316f675 -r 129e611eaf50 ui/createinstallerdialog.cpp --- a/ui/createinstallerdialog.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/createinstallerdialog.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -19,10 +19,25 @@ #include #include #include +#include + +/* Static information used in codesigning */ +#ifndef SIGN_HASH +#define SIGN_HASH "sha256" +#endif +#ifndef SIGN_URL +#define SIGN_URL "https://wald.intevation.org/projects/trustbridge/" +#endif +#ifndef SIGN_PUBLISHER +#define SIGN_PUBLISHER "TrustBridge Test with ümlaut" +#endif + CreateInstallerDialog::CreateInstallerDialog(QMainWindow *parent) : QDialog(parent), - mProgress(this) + mProgress(this), + mInstallerPath(), + mCurrentWorkingDir(NULL) { QSettings settings; setWindowTitle(tr("Create binary installer")); @@ -116,7 +131,6 @@ setLayout(topLayout); mProgress.setWindowModality(Qt::WindowModal); - mProgress.setLabelText(tr("Creating installer package...")); mProgress.setCancelButton(0); mProgress.setRange(0,0); mProgress.setMinimumDuration(0); @@ -162,9 +176,18 @@ void CreateInstallerDialog::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { + if (mCurrentWorkingDir) { + delete mCurrentWorkingDir; + mCurrentWorkingDir = NULL; + } FinishedDialog *fin = new FinishedDialog(0, tr("Created installer in %1.") .arg(mSaveFile->text()), mNSISProc.readAll(), false); qDebug() << "Finished: " << mNSISProc.readAll(); + mProgress.setLabelText(tr("Signing installer package...")); + if (!signFile(mInstallerPath)) { + showErrorMessage(tr("Failed to sign installer package.")); + QFile::remove(mInstallerPath); + } mProgress.cancel(); fin->show(); close(); @@ -172,12 +195,17 @@ void CreateInstallerDialog::processError(QProcess::ProcessError error) { + if (mCurrentWorkingDir) { + delete mCurrentWorkingDir; + mCurrentWorkingDir = NULL; + } qDebug() << "Error: " << mNSISProc.readAll(); mProgress.cancel(); } void CreateInstallerDialog::createInstaller() { + mProgress.setLabelText(tr("Creating installer package...")); QDir binDir(mBinaryFolder->text()); QDir outDir(mSaveFile->text()); if (mBinaryFolder->text().isEmpty() || !binDir.exists()) { @@ -201,28 +229,39 @@ return; } + QTemporaryDir *signedFilesDir = codesignBinaries(binDir.path() + "/windows"); + + if (!signedFilesDir) { + /* Error messages should have been shown by the codesign function */ + return; + } + + mProgress.setLabelText(tr("Creating NSIS package...")); + /* Copy windows directory contents to tmpdir */ QStringList arguments; mNSISProc.setProgram("makensis"); mNSISProc.setProcessChannelMode(QProcess::MergedChannels); mNSISProc.setWorkingDirectory(outDir.path()); #ifdef Q_OS_WIN - arguments << QString::fromLatin1("/Dfiles_dir=") + binDir.path().replace("/", "\\") + "\\windows"; + arguments << QString::fromLatin1("/Dfiles_dir=") + signedFilesDir->path().replace("/", "\\"); arguments << "/Dpath_sep=\\"; foreach (const QString &key, keys) { QString value = options.value(key, QString()).toString(); if (key == "setupname") { value = value.arg(outDir.path().replace("/", "\\") + "\\"); + mInstallerPath = value; } arguments << QString::fromLatin1("/D%1=%2").arg(key, value); } #else - arguments << QString::fromLatin1("-Dfiles_dir=") + binDir.path() + "/windows"; + arguments << QString::fromLatin1("-Dfiles_dir=") + signedFilesDir->path(); arguments << "-Dpath_sep=/"; foreach (const QString &key, keys) { QString value = options.value(key, QString()).toString(); if (key == "setupname") { value = value.arg(outDir.path() + "/"); + mInstallerPath = value; } arguments << QString::fromLatin1("-D%1=%2").arg(key, value); } @@ -242,6 +281,85 @@ } } +bool CreateInstallerDialog::signFile(QString filePath) { + QProcess signProc; + signProc.setProcessChannelMode(QProcess::MergedChannels); + signProc.setProgram("osslsigncode"); + QStringList arguments; + + QSettings mySettings; + + QString publisher = mySettings.value("sign_publisher", SIGN_PUBLISHER).toString(); + QString url = mySettings.value("sign_url", SIGN_URL).toString(); + QString hash = mySettings.value("sign_hash", SIGN_HASH).toString(); + + arguments << "sign" << "-certs" << mCertFile->text() << "-key" + << mCertFile->text() << "-n" << publisher << "-i" << + url << "-h" << hash << "-in" << filePath << "-out" << filePath + ".signed"; + + qDebug() << "Starting osslsigncode with arguments: " << arguments; + signProc.setArguments(arguments); + signProc.start(); + + if (!signProc.waitForFinished(30000)) { + qDebug() << "Signing takes longer then 30 seconds. Aborting."; + return false; + } + + if (signProc.exitStatus() != QProcess::NormalExit || + signProc.exitCode() != 0) { + qDebug() << "Error process returned: " << signProc.exitCode(); + qDebug() << "Output: " << signProc.readAllStandardOutput(); + return false; + } + + if (!QFile::remove(filePath)) { + qDebug() << "Failed to remove file."; + return false; + } + if (!QFile::copy(filePath + ".signed", filePath)) { + qDebug() << "Failed to copy signed file in place."; + return false; + } + if (!QFile::remove(filePath + ".signed")) { + qDebug() << "Failed to remove signed."; + return false; + } + return true; +} + + +QTemporaryDir *CreateInstallerDialog::codesignBinaries(const QDir& sourceDir) { + QTemporaryDir* target = new QTemporaryDir(); + /* Copy all files from the source dir to a temporary location */ + mProgress.setLabelText(tr("Signing binaries...")); + + mProgress.show(); + foreach (const QFileInfo& entry, sourceDir.entryInfoList()) { + QString targetPath = target->path() + QString::fromLatin1("/") + entry.fileName(); + if (entry.fileName() == "." || entry.fileName() == "..") { + continue; + } + if (!QFile::copy(entry.absoluteFilePath(), targetPath)) { + qDebug() << "Failed to copy: " << entry.absoluteFilePath() << " to: " << targetPath; + showErrorMessage(tr("Failed to copy binaries to temporary location.")); + mProgress.cancel(); + return NULL; + } + if (entry.suffix() == "exe") { + if (!signFile(targetPath)) { + showErrorMessage(tr("Failed to sign binaries with osslsigncode.\n" + "Please check that %1 is a valid code signing certificate and that" + "osslsigncode can be found in the PATH.").arg(mCertFile->text())); + mProgress.cancel(); + return NULL; + } + } + } + mProgress.cancel(); + return target; +} + FinishedDialog::FinishedDialog(QDialog *parent, QString msg, QString details, bool isErr): QDialog(parent) diff -r 39f03316f675 -r 129e611eaf50 ui/createinstallerdialog.h --- a/ui/createinstallerdialog.h Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/createinstallerdialog.h Wed Jun 25 15:16:24 2014 +0200 @@ -13,12 +13,14 @@ #include #include #include +#include /** * @file createinstallerdialog.h * @brief The dialog to show settings and create an installer. */ class QListWidget; +class QTemporaryDir; class CreateInstallerDialog : public QDialog { @@ -38,6 +40,8 @@ QProcess mNSISProc; QProgressDialog mProgress; + QString mInstallerPath; + QTemporaryDir *mCurrentWorkingDir; /** @brief show an error message with QMessageBox * @@ -49,8 +53,44 @@ void openCertificateSelect(); void openFolderSelect(); void openSaveLocation(); + + /**@brief entry point for installer creation + * + * check the selected parameters (certificate / folder etc.) and + * create the nsis installer. This also creates the signatures. */ void createInstaller(); + /**@brief Create tempoary dir with signed binaries from sourcedir + * + * Copies all files from the sourceDir to a temporary directory + * and signs all .exe files in that directory. + * + * The caller needs to delete the temporary directory. If an error + * occurs NULL is returned. + * + * @param[in] sourceDir the directory with the binaries to sign + * @returns a pointer to a temporary dir containing the signed binaries + * or NULL. + */ + QTemporaryDir *codesignBinaries(const QDir& sourceDir); + + /**@brief Sign a file with the codesigning certificate from mCertFile + * + * Calls osslsigncode to sign the file pointed to in filePath. + * The signing operation is logged. + * + * Sign information (hash algo / publisher / url) can be set at + * build time or in the settings with the variables: + * + * sign_hash # the hash algorithm to use. Values are the same as in singtool + * sign_publisher # the publisher information + * sign_url # the product url to use in the signature + * + * @param[in] filePath the absolute path to the file. + * @returns true on success, false on error + */ + bool signFile(QString filePath); + /* Slots for the creator process */ void processError(QProcess::ProcessError error); void processFinished(int exitCode, QProcess::ExitStatus exitStatus); diff -r 39f03316f675 -r 129e611eaf50 ui/helpdialog.h --- a/ui/helpdialog.h Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/helpdialog.h Wed Jun 25 15:16:24 2014 +0200 @@ -17,6 +17,7 @@ class HelpDialog : public QDialog { + Q_OBJECT public: /** @brief Create a help dialog */ HelpDialog(QMainWindow *parent); diff -r 39f03316f675 -r 129e611eaf50 ui/img/icon.rc --- a/ui/img/icon.rc Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/img/icon.rc Wed Jun 25 15:16:24 2014 +0200 @@ -1,1 +1,2 @@ +#include "events.rc" IDI_ICON1 ICON DISCARDABLE "icon.ico" diff -r 39f03316f675 -r 129e611eaf50 ui/installwrapper.cpp --- a/ui/installwrapper.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/installwrapper.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -150,20 +150,46 @@ } #else /* WIN32 */ QProcess installerProcess; - installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); QStringList parameters; choicesFile.setAutoRemove(false); parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName(); - installerProcess.setArguments(parameters); - - qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; - installerProcess.start(); - if (!installerProcess.waitForStarted() || - installerProcess.state() == QProcess::NotRunning) { - emit error (tr("Failed to start installer process.")); - return; + bool sudo_started = false; + bool use_sudo = is_admin(); + if (use_sudo) { + QStringList sudoPrograms; + sudoPrograms << "gksudo" << "kdesudo" << "sudo"; + QStringList sudoParams; + sudoParams << cinstProcInfo.absoluteFilePath() << parameters; + installerProcess.setArguments(sudoParams); + + foreach (const QString &sProg, sudoPrograms) { + installerProcess.setProgram(sProg); + qDebug() << "Starting process " << sProg <<" params: " << sudoParams; + installerProcess.start(); + if (!installerProcess.waitForStarted() || + installerProcess.state() == QProcess::NotRunning) { + continue; + } else { + sudo_started = true; + break; + } + } + } + + /* Fallback to start without sudo */ + if (!use_sudo || !sudo_started) { + installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); + installerProcess.setArguments(parameters); + + qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; + installerProcess.start(); + if (!installerProcess.waitForStarted() || + installerProcess.state() == QProcess::NotRunning) { + emit error (tr("Failed to start installer process.")); + return; + } } installerProcess.waitForFinished(); diff -r 39f03316f675 -r 129e611eaf50 ui/l10n/administrator_de_DE.ts --- a/ui/l10n/administrator_de_DE.ts Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/l10n/administrator_de_DE.ts Wed Jun 25 15:16:24 2014 +0200 @@ -18,26 +18,26 @@ TrustBridge ist ein sicherer Wurzelzertifikatsinstaller für Windows und Linux. - + TrustBridge is a root certificate installer for Windows and Linux. TrustBridge ist ein Wurzelzertifikatsinstaller für Windows und Linux. - + The root certificate lists are managed by the German <a href="https://www.bsi.bund.de">Federal Office for Information Security (BSI)</a>. Die Liste der Wurzelzertifikate wird vom <a href="https://www.bsi.bund.de">Bundesamt für Sicherheit in der Informationstechnik (BSI)</a> verwaltet. - + The software was developed by the companies <a href="http://www.intevation.de">Intevation GmbH</a> and <a href="http://www.dn-systems.de">DN-Systems GmbH</a>, <br> contracted by the German Federal Office for Information Security (BSI). Die Software wurde entwickelt von den Unternehmen <a href="http://www.intevation.net">Intevation GmbH</a> und <a href="http://www.dn-systems.com">DN-Systems GmbH</a>, <br> beauftragt durch das Bundesamt für Sicherheit in der Informationstechnik (BSI). - + TrustBridge is Free Software licensed under GNU GPL v2+. Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik @@ -46,7 +46,7 @@ Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik (BSI) - + Close Schließen @@ -54,78 +54,139 @@ AdministratorWindow - - + + TrustBridge Administration TrustBridge Verwaltung - + Menu Menü - + Create installer ... Installationspaket erstellen ... - + About TrustBridge Ãœber TrustBridge - + Quit Beenden - + All managed root certificates of the certificate list: The english original should be improved In der Liste enthaltene Zertifikate: - + Select certificate list file Zertifikatsliste auswählen - + + + Error! Fehler! - + Failed to load the certificate list. Fehler beim Laden der Zertifikatsliste. + + Failed to open log file: + Fehler beim Öffnen der Log-Datei: + + + + + Changes are not logged! + Änderungen wurden nicht geloggt! + + + + Failed to write log file: + Fehler beim Schreiben der Log-Datei: + + + + new certificatelist + neue Zertifikatsliste + + + + based on list from + basiert auf der Liste vom + + + + signing certificate: + + + + + + new certificates: + + + + + + certificates marked to remove: + + + + + signing certificate: + + signiertes Zertifikat: + + + new certificates: + + neues Zertifikat: + + + certificates marked to remove: + + Zertifikate als gelöscht markiert: + + All managed root certificates of the certificate list: Alle verwalteten Wurzelzertifikate der Zertifikatsliste: - + Management application of the BSI certificate installer Verwaltungsanwendung des BSI-Zertifikatsinstallers - + Save list Liste speichern - + Load list Liste laden - + Add certificate Zertifikat hinzufügen - + Remove certificate Zertifikat entfernen @@ -134,12 +195,45 @@ Zertifikatslistendatei auswählen - + Select certificate Zertifikat auswählen + CertificateDiffDialog + + + TrustBridge - List changes + TrustBridge - Listenänderungen + + + + The following certificates are changed: + Die folgenden Zertifikate wurden geändert: + + + + New + Neu + + + + Remove + Entfernen + + + + Ok + Ok + + + + Cancel + Abbrechen + + + CertificateTabelModel @@ -313,8 +407,8 @@ CreateInstallerDialog - - + + Create binary installer Installationspaket erstellen @@ -331,93 +425,126 @@ Code Signing Zertifikat auswählen (privater Schlüssel): - + Create and sign a TrustBridge binary installer. Erzeugt und signiert ein TrustBridge-Installationspaket. - + Select binary folder: Binärverzeichnis auswählen: - + Select code signing certificate: Code-Signing-Zertifikat auswählen: - + Select output folder: Ausgabeverzeichnis auswählen: - + Create installer Installationspaket erzeugen - + Cancel Abbrechen - + Creating installer package... Installationspaket wird erstellt... - + Select certificate Zertifikat auswählen - + Select binary folder Binärverzeichnis auswählen - + Error! Fehler! - + Created installer in %1. Installationspaket erstellt in %1. - + + Signing installer package... + Installationspaket signieren... + + + + Failed to sign installer package. + Fehler beim Signieren des Installationspakets. + + + Please select an existing input folder. Bitte wählen Sie ein existierendes Eingabeverzeichnis. - + Please select a codesigning certificate. Bitte wählen Sie ein Code-Signing-Zertifikat. - + Please select a output folder. Bitte wählen Sie ein Ausgabeverzeichnis. - + Folder %1 does not appear to contain a meta.ini Das Verzeichnis %1 enthält keine meta.ini Datei - + + Creating NSIS package... + NSIS-Paket wird erstellt... + + + Failed to start makensis. Please ensure that makensis is installed and in your PATH variable. Fehler beim Starten von makensis. Bitte versichern Sie sich, dass makensis korrekt installiert und in der PATH-Variable enthalten ist. + + Signing binaries... + Binärpakete werden signiert... + + + + Failed to copy binaries to temporary location. + Fehler beim Kopieren der Binärdaten in temporären Ort. + + + + Failed to sign binaries with osslsigncode. +Please check that %1 is a valid code signing certificate and thatosslsigncode can be found in the PATH. + TODO: missing blank in EN string + Fehler beim Signieren der Binärpakete mit osslsigncode. +Bitte prüfen Sie, dass %1 ein gültiges Code-Signing-Zertifikat ist und osslsigncode im PATH gefunden wird. + + Select source archive Archiv auswählen - + Select target location Zielort auswählen @@ -425,22 +552,22 @@ FinishedDialog - + Success! Erfolgreich! - + Error! Fehler! - + Details Details - + OK OK diff -r 39f03316f675 -r 129e611eaf50 ui/l10n/trustbridge_de_DE.ts --- a/ui/l10n/trustbridge_de_DE.ts Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/l10n/trustbridge_de_DE.ts Wed Jun 25 15:16:24 2014 +0200 @@ -18,26 +18,26 @@ TrustBridge ist eine sicherer Wurzelzertifikatsinstaller für Windows und Linux. - + TrustBridge is a root certificate installer for Windows and Linux. - TrustBridge ist eine Wurzelzertifikatsinstaller für Windows und Linux. + TrustBridge ist eine Wurzelzertifikatsinstaller für Windows und Linux. - + The root certificate lists are managed by the German <a href="https://www.bsi.bund.de">Federal Office for Information Security (BSI)</a>. Die Liste der Wurzelzertifikate wird vom <a href="https://www.bsi.bund.de">Bundesamt für Sicherheit in der Informationstechnik (BSI)</a> verwaltet. - + The software was developed by the companies <a href="http://www.intevation.de">Intevation GmbH</a> and <a href="http://www.dn-systems.de">DN-Systems GmbH</a>, <br> contracted by the German Federal Office for Information Security (BSI). Die Liste der Wurzelzertifikate wird vom <a href="https://www.bsi.bund.de">Bundesamt für Sicherheit in der Informationstechnik (BSI)</a> verwaltet. - + TrustBridge is Free Software licensed under GNU GPL v2+. Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik @@ -46,7 +46,7 @@ Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik (BSI) - + Close Schließen @@ -116,7 +116,7 @@ MainWindow - + An updated certificate list is available. Click here to install. Eine aktualisierte Zertifikatsliste ist verfügbar. Klicken Sie hier zum Installieren. @@ -134,34 +134,34 @@ Möchten Sie die neue Version installieren? - + Check for Updates Aktualisierungen prüfen - - - + + + Quit Beenden - + TrustBridge TrustBridge - + Menu Menü - + Force Update Aktualisierung erzwingen - + Settings Einstellungen @@ -170,131 +170,144 @@ Statusdialog - - <h3>An update for %1 is available.</h3> + + An update for %1 is available. Click here to download and install the update. - + Eine Aktualisierung für %1 ist verfügbar. +Hier klicken, um Download und Installation zu starten. - + Help Hilfe - + About "TrustBridge" ergänzen Ãœber TrustBridge - + Managed Certificates Verwaltete Zertifikate - - - + + + Current List Date: %1 Datum der aktuellen Liste: %1 - + Autoupdate Automatische Aktualisierung - + Autostart Start der Anwendung bei Systemstart - + Install selected Jetzt installieren - + Details Details - + Subject Common Name: Inhaber CN: - + Subject Organisation: Inhaber Organisation: - + Issuer Common Name: Aussteller CN: - + Issuer Organisation: Aussteller Organisation: - + Valid from: Gültig ab: - + Valid to: Gültig bis: - + Fingerprint: Fingerprint: - + New List Date: %1 Datum der neuen Liste: %1 - + New certificates to install Neu zu installierende Zertifikate - + New certificates to remove Neu zu löschende Zertifikate - + Old certificates to install Bisher installierte Zertifikate - + Old certificates to remove Bisher gelöschte Zertifikate - + Error executing update Fehler bei der Aktualisierung - + Installing certificates... Zertifikate werden installiert... + ProcessWaitDialog + + + Applications need to be closed. + + + + + Close all running firefox and thunderbird instances to continue installation! + + + + QObject - Couldn't detect any system tray on this system. This software can only be used in a desktop environment. - Es konnte kein SystemTray auf diesem System gefunden werden. Diese Software kann nur in einer Desktopumgebung verwendet werden. + Es konnte kein SystemTray auf diesem System gefunden werden. Diese Software kann nur in einer Desktopumgebung verwendet werden. diff -r 39f03316f675 -r 129e611eaf50 ui/main.cpp --- a/ui/main.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/main.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -6,6 +6,9 @@ * See LICENSE.txt for details. */ #include "mainwindow.h" +#include "processhelp.h" +#include "logging.h" +#include "selftest.h" #include #include @@ -35,6 +38,14 @@ int main(int argc, char **argv) { + /* First verify integrity even before calling QApplication*/ + if (!selftest()) { + syslog_error_printf ("Integrity check failed."); +#ifdef RELEASE_BUILD + return -1; +#endif + } + QApplication app (argc, argv); QApplication::setQuitOnLastWindowClosed(false); @@ -55,6 +66,12 @@ return 0; } + if (ProcessHelp::otherProcessesExist(APPNAME)) { + qDebug() << "Another " << APPNAME << " process is already running. Exiting."; + ProcessHelp::activateWindowForProcess(APPNAME); + return 0; + } + QTranslator translator; if (QLocale::system().name() == "C") { /* Useful for testing / development as the primary target is german */ diff -r 39f03316f675 -r 129e611eaf50 ui/mainwindow.cpp --- a/ui/mainwindow.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/mainwindow.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -29,6 +29,19 @@ #include #include +#include "certificatelist.h" +#include "downloader.h" +#include "helpdialog.h" +#include "aboutdialog.h" +#include "certificateitemdelegate.h" +#include "separatoritemdelegate.h" +#include "installwrapper.h" +#include "util.h" +#include "logging.h" +#include "binverify.h" +#include "processhelp.h" +#include "processwaitdialog.h" + // The amount of time in minutes stay silent if we have // something to say #define NAG_INTERVAL_MINUTES 70 @@ -38,23 +51,24 @@ #endif #define SERVER_URL "https://files.intevation.de:443" -#define LIST_RESOURCE "/users/aheinecke/zertifikatsliste.txt" -#define SW_RESOURCE "/users/aheinecke/TrustBridge.exe" -#ifdef Q_OS_WIN -#define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.exe" -#else -#define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.sh" -#endif -#include "certificatelist.h" -#include "downloader.h" -#include "helpdialog.h" -#include "aboutdialog.h" -#include "certificateitemdelegate.h" -#include "separatoritemdelegate.h" -#include "installwrapper.h" -#include "util.h" -#include "logging.h" +#ifdef RELEASE_BUILD +# define LIST_RESOURCE "/users/aheinecke/zertifikatsliste.txt" +# define SW_RESOURCE "/users/aheinecke/TrustBridge.exe" +# ifdef Q_OS_WIN +# define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.exe" +# else +# define SW_RESOURCE_VERSION "/users/aheinecke/TrustBridge-%1.sh" +# endif +#else // RELEASE_BUILD +# define LIST_RESOURCE "/users/aheinecke/development/zertifikatsliste.txt" +# define SW_RESOURCE "/users/aheinecke/development/TrustBridge.exe" +# ifdef Q_OS_WIN +# define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.exe" +# else +# define SW_RESOURCE_VERSION "/users/aheinecke/development/TrustBridge-development.sh" +# endif +#endif MainWindow::MainWindow(bool trayMode): mTrayMode(trayMode) @@ -103,26 +117,34 @@ } if (mCurState == NewSoftwareAvailable) { - checkUpdates(true); - mCurState = DownloadingSW; + verifySWData(); + QString swFileName = mSettings.value("Software/available").toString(); + if (swFileName.isEmpty()) { + checkUpdates(true); + mCurState = DownloadingSW; + return; + } + installNewSW(swFileName, + mSettings.value("Software/availableDate").toDateTime()); } } void MainWindow::showMessage() { - if (!isVisible() && !mCurMessage.isEmpty()) { + if (mCurMessage.isEmpty()) { + return; + } + if (mCurState == NewSoftwareAvailable || !isVisible()) { mTrayIcon->showMessage(QApplication::applicationName(), mCurMessage, - QSystemTrayIcon::Information, 5000); + QSystemTrayIcon::Information, 10000); mMessageTimer->start(); // Restart the timer so that we don't spam } } -void MainWindow::verifyAvailableData() +void MainWindow::verifyListData() { QString availableFileName = mSettings.value("List/available").toString(); QString installedFileName = mSettings.value("List/installed").toString(); - QString swFileName = mSettings.value("Software/available").toString(); - if (!availableFileName.isEmpty()) { mListToInstall.readList(availableFileName.toLocal8Bit().constData()); if (!mListToInstall.isValid()) { @@ -154,12 +176,40 @@ mSettings.remove("List/installed"); mSettings.remove("List/installedDate"); } +} - if (!swFileName.isEmpty()) { - // TODO Verify integrity of the software - } else { +void MainWindow::verifySWData() +{ + QString swFileName = mSettings.value("Software/available").toString(); + + if (swFileName.isEmpty()) { + mSettings.remove("Software/availableDate"); + return; + } + + QFileInfo fi(swFileName); + if (!fi.exists()) { mSettings.remove("Software/available"); mSettings.remove("Software/availableDate"); + qDebug() << "Software does not yet exist."; + return; + } + if (!fi.isExecutable()) { + qWarning() << "Downloaded file: " << swFileName << " is not executable."; + QFile::remove(swFileName); + mSettings.remove("Software/available"); + mSettings.remove("Software/availableDate"); + return; + } + bin_verify_result verifyResult = verify_binary(swFileName.toUtf8().constData(), + swFileName.toUtf8().size()); + qDebug() << "Binary verify result: " << verifyResult; + if (verifyResult != VerifyValid) { + qDebug() << "Failed to verify downloaded data."; + QFile::remove(swFileName); + mSettings.remove("Software/available"); + mSettings.remove("Software/availableDate"); + return; } } @@ -168,7 +218,7 @@ mSettings.setValue("List/available", fileName); mSettings.setValue("List/availableDate", modDate); - verifyAvailableData(); + verifyListData(); if (!mListToInstall.isValid()) { /* Downloader provided invalid files */ /* TODO: Error count. Error handling. Otherwise @@ -198,20 +248,29 @@ void MainWindow::installNewSW(const QString& fileName, const QDateTime& modDate) { QFileInfo instProcInfo = QFileInfo(fileName); - if (!instProcInfo.isExecutable()) { - qWarning() << "Downloaded file: " << fileName << " is not executable."; - setState(TransferError); + QString filePath = QDir::toNativeSeparators(instProcInfo.absoluteFilePath()); + + if (verify_binary(filePath.toUtf8().constData(), + filePath.toUtf8().size()) != VerifyValid) { + qDebug() << "Invalid software. Not installing"; return; - } - QString filePath = QDir::toNativeSeparators(instProcInfo.absoluteFilePath()); + } + QFileInfo fi(QCoreApplication::applicationFilePath()); + QDir installDir = fi.absoluteDir(); + #ifdef WIN32 + QString parameters = QString::fromLatin1("/S /UPDATE=1 /D=") + + installDir.path().replace("/", "\\") + ""; + SHELLEXECUTEINFOW shExecInfo; memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); shExecInfo.lpFile = reinterpret_cast (filePath.utf16()); + shExecInfo.lpParameters = reinterpret_cast (parameters.utf16()); - shExecInfo.fMask = SEE_MASK_NOASYNC; + // shExecInfo.fMask = SEE_MASK_NOASYNC; + shExecInfo.nShow = SW_SHOWDEFAULT; if (!is_admin()) { shExecInfo.lpVerb = L"open"; @@ -219,7 +278,8 @@ shExecInfo.lpVerb = L"runas"; } - qDebug() << "Starting process: " << filePath; + qDebug() << "Starting process: " << filePath + << " with arguments: " << parameters; if (!ShellExecuteExW(&shExecInfo)) { /* Execution failed, maybe the user aborted the UAC check? */ @@ -231,9 +291,13 @@ return; } #else /* WIN32 */ - qDebug() << "Starting process " << filePath; + QStringList parameters; + parameters << "/S" << "/UPDATE=1" + << QString::fromLatin1("/D=%1").arg(installDir.path()); - if (!QProcess::startDetached(filePath)) { + qDebug() << "Starting process " << filePath << " args: " << parameters; + + if (!QProcess::startDetached(filePath, parameters)) { qDebug() << "Failed to start process."; return; } @@ -245,7 +309,7 @@ void MainWindow::checkUpdates(bool downloadSW) { - verifyAvailableData(); + verifyListData(); if (!mSettings.contains("Software/installedDate") || mSettings.value("Software/installedVersion").toString() != QApplication::applicationVersion()) { @@ -495,7 +559,7 @@ installButton->setIcon(QIcon(":/img/edit-redo.png")); #endif connect(quitButton, SIGNAL(clicked()), this, SLOT(closeApp())); - connect(installButton, SIGNAL(clicked()), this, SLOT(installCerts())); + connect(installButton, SIGNAL(clicked()), this, SLOT(checkAndInstallCerts())); connect(searchUpdates, SIGNAL(clicked()), this, SLOT(checkUpdates())); updatesHeaderActionLayout->addWidget(installButton); @@ -980,9 +1044,32 @@ qApp->quit(); } +void MainWindow::checkAndInstallCerts() +{ + /* Checking before opening the dialog should be cheaper */ + QList pids = ProcessHelp::getProcessesIdForName("firefox"); + pids.append(ProcessHelp::getProcessesIdForName("thunderbird")); + + if (pids.isEmpty()) { + installCerts(); + return; + } + + QStringList pNames; + pNames << "firefox" << "thunderbird"; + + ProcessWaitDialog *waitDialog = new ProcessWaitDialog(this, pNames); + + connect(waitDialog, SIGNAL(accepted()), this, SLOT(installCerts())); + connect(waitDialog, SIGNAL(accepted()), waitDialog, SLOT(deleteLater())); + + waitDialog->exec(); + return; +} + void MainWindow::togglePages(int button) { - mUpdatesPanel->hide(); + UpdatesPanel->hide(); mInstallPanel->hide(); mRemovePanel->hide(); mInfoPanel->hide(); @@ -1037,3 +1124,4 @@ mUpdatesWidget->resize(old.width(), old.height() - mUpdatesManual->height()); } } +>>>>>>> other diff -r 39f03316f675 -r 129e611eaf50 ui/mainwindow.h --- a/ui/mainwindow.h Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/mainwindow.h Wed Jun 25 15:16:24 2014 +0200 @@ -83,6 +83,13 @@ void toggleUpdatesManual(); void listChanged(int selected); + /** @brief check for running software that needs to close before installing + * + * This function calls installCerts if no software is running otherwise + * it informs the user about the software that still needs to be closed. + */ + void checkAndInstallCerts(); + /** @brief get the last modified date on the download server for * the current version. * @@ -136,15 +143,25 @@ void installNewSW(const QString& fileName, const QDateTime& modDate); private: - /** @brief check the integrity of available files. + /** @brief check the integrity of available certificate lists. * - * Do not use this as a trust check as this only works on + * Note: Do not use this as a local trust check as this only works on * FileNames where the underlying files can change. This * is just meant to check if the downloaded data was somehow * removed or corrupted. It also initializes mListToInstall * and mInstalledList. */ - void verifyAvailableData(); + void verifyListData(); + + /** @brief check the integrity of available software updates. + * + * Note: Do not use this as a local trust check as this only works on + * FileNames where the underlying files can change. This + * is just meant to check if the downloaded data was somehow + * removed or corrupted. + */ + void verifySWData(); + void createTrayIcon(); void createActions(); void createContent(); diff -r 39f03316f675 -r 129e611eaf50 ui/processhelp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/processhelp.h Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,49 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + * + * Parts of this code (especially windows) are based on kpimutils processes.cpp + * available under LGPL 2.1 or later. + */ +#ifndef PROCESSHELP_H +#define PROCESSHELP_H + +#include +#include + +/** + * @file Static helper functions for process handling + * @brief process handling functions + */ + +namespace ProcessHelp +{ +/** +* @brief look up process id's for a processName +* +* Looks up processes run by the current user. +* +* @param[in] processName the name of the process to look for +* @returns a list of pids that match this process. May be empty +*/ +const QList getProcessesIdForName(const QString &processName); + +/** +* @brief check if another process with the same name exists +* +* @param[in] processName name of the process to look for. +* +* @returns true if one or more processes (other than the current process) exist +*/ +bool otherProcessesExist(const QString &processName); + +/** +* @brief Activates the window for first found process +* @param [in] executableName executableName (without path and .exe extension) +*/ +void activateWindowForProcess(const QString &executableName); +} +#endif // PROCESSHELP_H diff -r 39f03316f675 -r 129e611eaf50 ui/processhelp_linux.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/processhelp_linux.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,30 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ +#ifndef WIN32 + +#include "processhelp.h" + +const QList ProcessHelp::getProcessesIdForName(const QString &processName) { + // TODO + Q_UNUSED(processName); + return QList(); +} + +bool ProcessHelp::otherProcessesExist(const QString &processName) { + // TODO + Q_UNUSED(processName); + return false; +} + +void ProcessHelp::activateWindowForProcess(const QString &executableName) { + // TODO + Q_UNUSED(executableName); + return; +} + +#endif /* Not WIN32 */ diff -r 39f03316f675 -r 129e611eaf50 ui/processhelp_win.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/processhelp_win.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,171 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. */ + +#ifdef WIN32 +#include "processhelp.h" +#include "strhelp.h" + +#include +#include +#include +#include + +#include + +struct EnumWindowsStruct { + EnumWindowsStruct() : windowId(0) {} + DWORD pid; + HWND windowId; +}; + +PSID copySid(PSID from) +{ + if (!from) { + return 0; + } + + int sidLength = GetLengthSid(from); + PSID to = (PSID) xmalloc(sidLength); + CopySid(sidLength, to, from); + return to; +} + +static PSID getProcessOwner(HANDLE hProcess) +{ + HANDLE hToken = NULL; + PSID sid; + + OpenProcessToken(hProcess, TOKEN_READ, &hToken); + if (hToken) { + DWORD size; + PTOKEN_USER userStruct; + + // check how much space is needed + GetTokenInformation(hToken, TokenUser, NULL, 0, &size); + if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { + userStruct = reinterpret_cast(new BYTE[size]); + GetTokenInformation(hToken, TokenUser, userStruct, size, &size); + + sid = copySid(userStruct->User.Sid); + CloseHandle(hToken); + delete [] userStruct; + return sid; + } + } + return 0; +} + +BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) { + + DWORD pidwin; + + GetWindowThreadProcessId(hwnd, &pidwin); + if (pidwin == ((EnumWindowsStruct *)lParam)->pid) { + ((EnumWindowsStruct *)lParam)->windowId = hwnd; + return FALSE; + } + } + return TRUE; +} + + +static HANDLE getProcessHandle(int processID) +{ + return OpenProcess(SYNCHRONIZE | + PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ | + PROCESS_TERMINATE, + false, processID); +} + +const QList ProcessHelp::getProcessesIdForName(const QString &processName) +{ + HANDLE h; + PROCESSENTRY32 pe32; + QList pids; + + h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (h == INVALID_HANDLE_VALUE) { + return pids; + } + + pe32.dwSize = sizeof(PROCESSENTRY32); // Necessary according to MSDN + if (!Process32First(h, &pe32)) { + return pids; + } + + pids.clear(); + + const QString processNameLower = processName.toLower().replace(".exe", ""); + const QString processNameExe = processNameLower + ".exe"; + + do { + const QString exeFile = QString::fromWCharArray(pe32.szExeFile).toLower(); + if (exeFile == processNameLower || exeFile == processNameExe) { + PSID user_sid = getProcessOwner(GetCurrentProcess()); + if (user_sid) { + // Also check that we are the owner of that process + HANDLE hProcess = getProcessHandle(pe32.th32ProcessID); + if (!hProcess) { + continue; + } + + PSID sid = getProcessOwner(hProcess); + PSID userSid = getProcessOwner(GetCurrentProcess()); + if (!sid || (userSid && !EqualSid(userSid, sid))) { + free(sid); + continue; + } + } + pids.append((int)pe32.th32ProcessID); + qDebug() << "found PID: " << (int)pe32.th32ProcessID; + } + } while (Process32Next(h, &pe32)); + CloseHandle(h); + return pids; +} + +bool ProcessHelp::otherProcessesExist(const QString &processName) +{ + const QList pids = getProcessesIdForName(processName); + int myPid = getpid(); + foreach(int pid, pids) { + if (myPid != pid) { + qDebug() << "Found another process with id: " << pid; + return true; + } + } + return false; +} + +void ProcessHelp::activateWindowForProcess(const QString &executableName) +{ + const QList pids = getProcessesIdForName(executableName); + int myPid = getpid(); + int foundPid = 0; + foreach(int pid, pids) { + if (myPid != pid) { + qDebug() << "activateWindowForProcess(): PID to activate:" << pid; + foundPid = pid; + break; + } + } + if (foundPid == 0) { + return; + } + EnumWindowsStruct winStruct; + winStruct.pid = foundPid; + EnumWindows(EnumWindowsProc, (LPARAM)&winStruct); + if (winStruct.windowId == 0) { + return; + } + SetForegroundWindow(winStruct.windowId); +} +#endif // WIN32 + diff -r 39f03316f675 -r 129e611eaf50 ui/processwaitdialog.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/processwaitdialog.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,56 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ +#include +#include +#include +#include +#include +#include + +#include "processwaitdialog.h" +#include "processhelp.h" + +ProcessWaitDialog::ProcessWaitDialog(QWidget *parent, const QStringList& processNames) : + QDialog(parent), + mProcessNames(processNames) { + QHBoxLayout *theLayout = new QHBoxLayout(this); + + setWindowTitle(tr("Applications need to be closed.")); + setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint); + + QLabel *warnLabel = new QLabel(tr("Close all running firefox and thunderbird instances to continue installation!")); + QLabel *warnIcon = new QLabel(); + warnIcon->setPixmap(QApplication::style()->standardPixmap(QStyle::SP_MessageBoxWarning)); + + theLayout->addWidget(warnIcon); + theLayout->addWidget(warnLabel); + + theLayout->setSizeConstraint(QLayout::SetFixedSize); + // mProcessList = new QListWidget(); +// theLayout->addWidget(mProcessList); + updateProcesses(); +} + +void ProcessWaitDialog::updateProcesses() { + QList pids; + foreach (const QString& pName, mProcessNames) { + pids.append(ProcessHelp::getProcessesIdForName(pName)); + } + if (pids.isEmpty()) { + accept(); + return; + } + + /* mProcessList->clear(); + + foreach (int pId, pids) { + mProcessList->addItem(QString::fromLatin1("Pid ") + pId); + } +*/ + QTimer::singleShot(500, this, SLOT(updateProcesses())); +} diff -r 39f03316f675 -r 129e611eaf50 ui/processwaitdialog.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/processwaitdialog.h Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,45 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. */ +#ifndef PROCESSWAITDIALOG_H +#define PROCESSWAITDIALOG_H + +#include +#include + +/** @file Dialog to show that some processes need to be closed + * + * This dialog informs about processes that are still running and + * need to be closed. + */ + +class ProcessWaitDialog : public QDialog +{ + Q_OBJECT + +public: + /** @brief create the dialog + * + * The dialog is modal and will stay open until no more processes + * with names from processnames exist. + * + * @param[in] parent the parent dialog + * @param[in] processNames the names of the processes to wait for. + */ + ProcessWaitDialog(QWidget *parent, const QStringList& processNames); + +private slots: + + /** @brief update the process list */ + void updateProcesses(); + +private: + + QListWidget *mProcessList; + const QStringList mProcessNames; +}; + +#endif // PROCESSWAITDIALOG_H diff -r 39f03316f675 -r 129e611eaf50 ui/sslconnection.cpp --- a/ui/sslconnection.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/sslconnection.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -31,6 +31,7 @@ mPinnedCert(certificate), mInitialized(false), mConnected(false), + mNeedsReset(false), mServerFD(-1), mErrorState(NoError) { diff -r 39f03316f675 -r 129e611eaf50 ui/tests/CMakeLists.txt --- a/ui/tests/CMakeLists.txt Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/tests/CMakeLists.txt Wed Jun 25 15:16:24 2014 +0200 @@ -15,13 +15,18 @@ find_package(Qt5Test) include_directories(${Qt5Test_INCLUDE_DIRS}) find_program(HIAWATHA_EXECUTABLE hiawatha) +find_program(OSSLSIGNCODE_EXECUTABLE osslsigncode) if (NOT HIAWATHA_EXECUTABLE) - message (STATUS "WARNING: hiawatha webserver not found. Downloader tests will fail.") + message (STATUS "WARNING: hiawatha webserver not found. Downloader will not be run.") else() add_definitions(-DHIAWATHA_EXECUTABLE="${HIAWATHA_EXECUTABLE}") endif() +if (WIN32 AND NOT OSSLSIGNCODE_EXECUTABLE) + message (STATUS "WARNING: osslsigncode not found. Authenticode tests will not be run.") +endif() + macro(add_custom_test _source _additional_sources) set(_test ${_source}) get_filename_component(_name ${_source} NAME_WE) @@ -65,7 +70,46 @@ if (WIN32) add_custom_test(windowsstoretest.cpp "${CMAKE_SOURCE_DIR}/cinst/windowsstore.c") -endif (WIN32) + + if (OSSLSIGNCODE_EXECUTABLE) + add_custom_test (binverifytest.cpp "") + add_custom_command( + TARGET binverifytest + POST_BUILD + COMMAND ${OSSLSIGNCODE_EXECUTABLE} sign -certs ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning.pem + -key ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning.key + -h sha256 -in ${CMAKE_CURRENT_BINARY_DIR}/fakeinst.exe + -out ${CMAKE_CURRENT_BINARY_DIR}/fakeinst-signed.exe + ) + add_custom_command( + TARGET binverifytest + POST_BUILD + COMMAND ${OSSLSIGNCODE_EXECUTABLE} sign -certs ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning.pem + -key ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning-other.key + -h sha256 -in ${CMAKE_CURRENT_BINARY_DIR}/fakeinst.exe + -out ${CMAKE_CURRENT_BINARY_DIR}/fakeinst-other-key.exe + ) + add_custom_command( + TARGET binverifytest + POST_BUILD + COMMAND ${OSSLSIGNCODE_EXECUTABLE} sign -certs ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning-other.pem + -key ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning-other.key + -h sha256 -in ${CMAKE_CURRENT_BINARY_DIR}/fakeinst.exe + -out ${CMAKE_CURRENT_BINARY_DIR}/fakeinst-other-cert.exe + ) + add_custom_command( + TARGET binverifytest + POST_BUILD + COMMAND ${OSSLSIGNCODE_EXECUTABLE} sign -certs ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning.pem + -key ${CMAKE_CURRENT_SOURCE_DIR}/data/codesign/codesigning.key + -h sha256 -in ${CMAKE_CURRENT_BINARY_DIR}/fakeinst.exe + -out ${CMAKE_CURRENT_BINARY_DIR}/fakeinst-invalid.exe && + ${CMAKE_STRIP} ${CMAKE_CURRENT_BINARY_DIR}/fakeinst-invalid.exe + ) + endif() +else () + add_custom_test (binverifytest.cpp "") +endif () if (NSS_FOUND) include_directories(${NSS_INCLUDE_DIRS}) @@ -99,7 +143,7 @@ RESULT_VARIABLE result ERROR_VARIABLE output) if (NOT ${result} EQUAL 0) - message(FATAL_ERROR "Could not create symbolic link for: ${target} --> ${output}") + message(STATUS "Could not create symbolic link for: ${target} --> ${output}. NSS Test might fail.") endif() endif() endif() diff -r 39f03316f675 -r 129e611eaf50 ui/tests/binverifytest.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/binverifytest.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,71 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ +#include "binverify.h" +#include "binverifytest.h" + +#include + +#ifdef Q_OS_WIN +# define EXE_SUFFIX ".exe" +#else +# define EXE_SUFFIX "" +#endif + +/* Some general robustness checks */ +void BinVerifyTest::testMiscErrors() +{ + QVERIFY (verify_binary (NULL, 10) != VerifyValid); + QVERIFY (verify_binary ("foo", 10) != VerifyValid); + QVERIFY (verify_binary ("bar", -1) != VerifyValid); + /* On windows the next line will check that a valid microsoft + * signed executable is not valid for us (pinning). On linux + * it will just fail with a read error which we tested above */ +#ifdef Q_OS_WIN + QVERIFY (verify_binary ("c:\\Windows\\System32\\mmc.exe", + strlen("c:\\Windows\\System32\\mmc.exe")) != VerifyInvalidCertificate); +#endif + QVERIFY (verify_binary ("/dev/null", strlen("/dev/null")) != VerifyValid); +} + +/* Check that a signature with only a different key (of the same size) + * is not validated (Invalid signature because key and cert don't match)*/ +void BinVerifyTest::testOtherKey() +{ + QVERIFY(VerifyInvalidSignature == verify_binary ("fakeinst-other-key" EXE_SUFFIX, + strlen("fakeinst-other-key" EXE_SUFFIX))); +} + +/* Check that an invalid signature is not validated */ +void BinVerifyTest::testInvalidSig() +{ + QVERIFY(VerifyValid != verify_binary ("fakeinst-invalid" EXE_SUFFIX, + strlen("fakeinst-invalid" EXE_SUFFIX))); +} + +/* Check that a signature with a different (valid) certificate is not validated */ +void BinVerifyTest::testOtherCert() +{ + QVERIFY(VerifyInvalidCertificate == verify_binary ("fakeinst-other-cert" EXE_SUFFIX, + strlen("fakeinst-other-cert" EXE_SUFFIX))); +} + +/* Check that no signature is not validated */ +void BinVerifyTest::testNoSignature() +{ + QVERIFY(VerifyValid != verify_binary ("fakeinst" EXE_SUFFIX, + strlen("fakeinst" EXE_SUFFIX))); +} + +/* Check that a valid signed executable is verified */ +void BinVerifyTest::testValidBinary() +{ + QVERIFY (VerifyValid == verify_binary ("fakeinst-signed" EXE_SUFFIX, + strlen("fakeinst-signed" EXE_SUFFIX))); +} + +QTEST_GUILESS_MAIN (BinVerifyTest); diff -r 39f03316f675 -r 129e611eaf50 ui/tests/binverifytest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/binverifytest.h Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,26 @@ +/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU GPL (v>=2) + * and comes with ABSOLUTELY NO WARRANTY! + * See LICENSE.txt for details. + */ +#ifndef COMMONTEST_H +#define COMMONTEST_H + +#include + +class BinVerifyTest: public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void testNoSignature(); + void testMiscErrors(); + void testValidBinary(); + void testOtherKey(); + void testOtherCert(); + void testInvalidSig(); +}; +#endif + diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/NOTES --- a/ui/tests/data/NOTES Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/tests/data/NOTES Wed Jun 25 15:16:24 2014 +0200 @@ -87,3 +87,46 @@ mkdir nss certutil -d nss -A -i valid_ssl_rsa.pem -n "test" -t c,C certutil -d nss -D -n "test" + +# Code signing +mkdir codesign +cd codesign +# Root CA +gen_key filename=codesigning_root.key +cert_write issuer_name="CN=Public TrustBridge Test,O=Public secret do not trust this,C=DE" \ +selfsign=1 issuer_key=codesigning_root.key \ +not_before=20130101000000 not_after=20151231235959 \ +is_ca=1 max_pathlen=0 output_file=codesigning_root.pem + +# Codesign cert +gen_key filename=codesigning.key +cert_req filename=codesigning.key output_file=codesigning.csr \ +subject_name="CN=Public TrustBridge codesigning test,O=Public secret do not trust this,C=DE" \ +key_usage=digital_signature \ +ns_cert_type=object_signing + +# Sign it: +cert_write request_file=codesigning.csr issuer_crt=codesigning_root.pem \ +issuer_key=codesigning_root.key output_file=codesigning.pem \ +not_before=20130101000000 not_after=20151231235959 \ +key_usage=digital_signature \ +ns_cert_type=object_signing + +osslsigncode sign -certs codesigning.pem -key codesigning.key \ + -n "TrustBridgeTest" -i https://wald.intevation.org/projects/trustbridge/ \ + -h sha256 \ + -in ~/ubuntu/src/m13-repo/build-windows/TrustBridge-0.6+21-aee3eb10bbba.exe \ + -out TrustBridge-0.6+21-aee3eb10bbba-signed.exe + +# Different test certificates. +gen_key filename=codesigning-other.key +cert_req filename=codesigning-other.key output_file=codesigning-other.csr \ +subject_name="CN=Public TrustBridge codesigning test,O=Public secret do not trust this,C=DE" \ +key_usage=digital_signature \ +ns_cert_type=object_signing + +cert_write request_file=codesigning-other.csr issuer_crt=codesigning_root.pem \ +issuer_key=codesigning_root.key output_file=codesigning-other.pem \ +not_before=20130101000000 not_after=20151231235959 \ +key_usage=digital_signature \ +ns_cert_type=object_signing diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning-other.key --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning-other.key Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKAIBAAKCAgEAqt/YYva86uZLj26KkNrJb6imHFbvPoxX7QBAIkhM+50GKZuO +P/QZKcdAeNZG7Oepqkc46DM1JgTPFsnWuZPm0xThx7Y8LTGhuAtwczdQDbadc8NP +G3uKvn2VmlQaN2yJmxVglNWWJu5tkC13fzPkDBN3+Wm7q+v0tY8FrA9iAPO6dRsr +BlGY0XOcBxR20ha7UEjV2ftsVKYgwKW9wnwF+kZU0w7OaTzLS8JIgoYPtJx2k5TB +Y6WgGQRrFdr/1SHV9ezALKlge9/vuJNM/OaSPLfgmOcxnl+Z2jiQoS7oiJIagIGH +quV1ScaAvsaCc7uQeneD3K1M03I2o/qZcXCBg5AdbtqtWZK2IiV/4cSYHm5g9mME +nSdSljwD/MHOjbdNG1mv+UHB958R0wMddiMTTq558lyiDuoeh54rxpc51bT+iMhl +jhkM7hqx0PEXwwDZ8ohO6JxCRz8k1HHTswV9g6315oEZJbMIbVOLbWUiHcJw+JD9 +t1+jJuxNdY1z3cs95lqlb+x+wIVP3OwdkecFmVm5PRWCR4d36xGCEe/pn3kV3KtV +xmFTO1Azr38iGGsMhdKoK3dsW4PVnhNoEV4ya5Up3WKgXc0RGrVMjpE02bWRE2Wv +1N8d4uGRNRJ9tsM7krx37bcxDSGL5iToWMapxkiGn76hxs2sRvzuq91p+M8CAwEA +AQKCAgEAiKip6Mwo3zz75WSlEaDJRbH91+B3SvD3SSbQJBrq5rj4usIcDG3uygj/ +OSU2aDYG7ZY0nxCFSzjBXxphzt3I17x1rkHC8uokyorrjloIfk80sebcF8DAgAT0 +Zw8oQHdfvlZkfeQsSEqb+ZlDXspjcn0HkMPNQnxdo+8UvD05RkWnNA1cZZtQuwLZ +IJhvRyrC+DyoO8PnKfQLcceccjS6myUwpfPLhUMH3DkvwKPzX6Fa/EEWQdmupxNv +iXUy8oQzGJIWSCHWdnvsvxOfmQvWnRT6XY9Zka4n3+0pTp+zfbZL18bAeB83pJ9L +TEh7AJBbxnZbUVyQevN3W8IKgj1WdkuIWHHsc+lMHSbB0U+7gTPIFgap53OEEg5q +fdxZdk7mEj4lnH3nVfojL4nQ6wfKL9vOVCFEGcBUOYsg3QHGQ1j2avItfnJ6Q04k +jvRwPmJoaewdIm2Q0bI9DDo1TPWtPKIMlIYSLVCQAO+u4E0vWfw0fzTWcoMVvg1L +eAQz0fuwFLxTkczJgI67qLxSjGjGiyDJ+2f+XaJlM4S/59SrqlMDTLOnSXAmmo6M +yIoB5PZ9uGxSYzZWJUuRbVAaos97fc3dxKp83G8iKLo1PzLLdaVmYgabSPXBDXYX +f3SmOJd6dcmKHNWJdOdFRzxhhzsUQTwWxkRYXEM4MW7BZ417cpECggEBAPx486Zg +ayFHK3P35lJGZ4lHOj697mYMnEQ4LtJwV0nro1UbfX3W6lBQeMz4MZxJloJpEA3Z +djGE+KxBPDa6hvQoICylEPfMvOC4cjtSf/pEOGcJ2H8UqVbuL+yXIcJmHGjAmZ5y +6cReu4hHFkbJeHRYvZRYleML6TwSuWREq8tEsJh5xGLHZlXgMFsfEuqh3l3Onbk8 +Zdl0b7Q0f/NP7qVpy4gwsAJUnzxYOVTIjUCUVwV4TZhBdIe36b8ey5GnPT52hgZp +SpjSZp5z2b1Nb28A2fis/5I4I01fnaYq3o/bXMC2M+OUvH4JO7FPwVt2KtDX1A4a +TRcPBeUzvaXWLqsCggEBAK1DCDCnC6lbeTlgFnpVxgUV75uO49RVc576s3pnm0i3 +2FVEfy/Fj79XCO8FDqQCTzN9L7biVM8nt+CuyWPA9JhKRZh6M8T8IxRx1AsA7E8A +9nd4eKbbgeVeAchoAvEVu0MroviOcPsScX2C9KmnpY0qr45mmMfL25HXo1xNl/b0 ++mxflqHCdk6sqSNE9inY0xD9wf/OfAQ3KrUJIVC85qC2WrzFtB0Yy5XZLiOoBJ/D +zh+lz/pCKaBKKnDoZ6fXpsG0m8lXDVzUZRStlPQMamX/da6g78SC4Goi2mx7QpHw +Os8bH9HrVExdpCSQ7Nmdur6DZxvccpgf+zl+0v0ATm0CggEAQW+v5t1ypstlbcdA +wO5Sg3gclopvsa9vCRduu0g2t4gFa1eWrPj4/hv9U1K4uQMxqVdFu/Ey+x61vR+j +VaP+umV0AV4/CZrdEXl80fdOCDWKUNpybG2Ufl15ul5pd5MzpcrVhgXOpQDQpj+W +fH5XZABkEoDrSE+cAd/wgRZzWFnTU5Gr3tZDpdpXbiadpoaRtcqJgqsu0q+lDBXX +W97JwcGr6P6Ff/Ui2GcdZOYeBjDsZRSLN/0vEMYQJWL77CJmczwQ/LRpizZtNoBc +XP4m9aRI2nUsQF+gdrtjht/xk2ONpL0UsdWpDRmjiQ9c1DHKYxqtcYJLnMBeDMve +SY87xQKCAQAi5a1wnzSqF9KCy+e7HCuWOqTYIB+jVNLE4pnjvZp5Ow5HnlQ/uvsI +/u69tbcNManiJQTHQS7zynwutQW7IdIiGlOKMpLayi4GoCalULpH71m1Fn62nN+8 +4wJY6xoslMPy84cPqSD4cO6K6SV+RlYB6OcTN3buRxEiftxYawiApTcLPPWJ/zD1 +B7HJeMpcA1//vBym+V/hOXtQm1YqfOG23QPJoch1U9kthWDVrbHAvB94IF2TemAH ++OgzdZvrInRj74yxMOdwGxeA4rVtslJ72MhLM/8XBYVN21dDIlB2NHyj2kK+dTe1 +aeb1tnr+GdbTKIRMCErMeSSQoAq/CqDBAoIBAGI603m4VyoBxpWqB5p11LW9tP5S +Rt79NBUUdB9onXfwn/bVkgRIOM7GzKmp8lFnz5q0wtqDwHd4AAKs76HsVnge9T/1 +TRrWX07bZ14EcIYS7ZjeVZfH+ZaoJ89l2v14cbf+MHA5f9IMb8Z5ei/+Ob1JFeHf +YPBShDgzP77W/yuw2XpwFvy1p6atby1HP/iaJ5gunhrCxFsL8pA57X9Fj8aDeidq +2MsXqzT8TLdzsNEPR5g3qq43fIGPjNnfwm+uRW1yvvaaschACCpodsSAIDJe4vuj +ckL2bH+SUw71GVzsXreEf+Ryv71Bt4wJzLpoZbMCbEjuTfDvr+hWEBAU9EU= +-----END RSA PRIVATE KEY----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning-other.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning-other.pem Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBZMSAwHgYDVQQDExdQdWJs +aWMgVHJ1c3RCcmlkZ2UgVGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBu +b3QgdHJ1c3QgdGhpczELMAkGA1UEBhMCREUwHhcNMTMwMTAxMDAwMDAwWhcNMTUx +MjMxMjM1OTU5WjBlMSwwKgYDVQQDEyNQdWJsaWMgVHJ1c3RCcmlkZ2UgY29kZXNp +Z25pbmcgdGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBub3QgdHJ1c3Qg +dGhpczELMAkGA1UEBhMCREUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCq39hi9rzq5kuPboqQ2slvqKYcVu8+jFftAEAiSEz7nQYpm44/9Bkpx0B41kbs +56mqRzjoMzUmBM8Wyda5k+bTFOHHtjwtMaG4C3BzN1ANtp1zw08be4q+fZWaVBo3 +bImbFWCU1ZYm7m2QLXd/M+QME3f5abur6/S1jwWsD2IA87p1GysGUZjRc5wHFHbS +FrtQSNXZ+2xUpiDApb3CfAX6RlTTDs5pPMtLwkiChg+0nHaTlMFjpaAZBGsV2v/V +IdX17MAsqWB73++4k0z85pI8t+CY5zGeX5naOJChLuiIkhqAgYeq5XVJxoC+xoJz +u5B6d4PcrUzTcjaj+plxcIGDkB1u2q1ZkrYiJX/hxJgebmD2YwSdJ1KWPAP8wc6N +t00bWa/5QcH3nxHTAx12IxNOrnnyXKIO6h6HnivGlznVtP6IyGWOGQzuGrHQ8RfD +ANnyiE7onEJHPyTUcdOzBX2DrfXmgRklswhtU4ttZSIdwnD4kP23X6Mm7E11jXPd +yz3mWqVv7H7AhU/c7B2R5wWZWbk9FYJHh3frEYIR7+mfeRXcq1XGYVM7UDOvfyIY +awyF0qgrd2xbg9WeE2gRXjJrlSndYqBdzREatUyOkTTZtZETZa/U3x3i4ZE1En22 +wzuSvHfttzENIYvmJOhYxqnGSIafvqHGzaxG/O6r3Wn4zwIDAQABo3AwbjAJBgNV +HRMEAjAAMB0GA1UdDgQWBBS0lOBu/DAejrDytCTEGB+6rDLVizAfBgNVHSMEGDAW +gBTl/kZGRoa0cm82zW7CPn3yqk4MeTAOBgNVHQ8BAQEEBAMCAYAwEQYJYIZIAYb4 +QgEBBAQDAgAQMA0GCSqGSIb3DQEBBQUAA4ICAQA2ublxGKfS6s5iAz8OAuMdGKg0 +oxacGX378xBctl7s+PORwx7kOo1X96d8KuQyWf9LXSZv1uPPRnEO+atMF2hswqcS +gFx/Y32vEz8dGeqye6qOGfQOBD7M4wZ7ww/CiTJJBVbQ54WrU3zoy5Fga/ijXOtY +i0AaZaoFfureK6+fCua9h+SRE7OljDCpSHigWTIY9MQ6fe7T8wXTnxhopdgT8k0R +NXL/UNEUm/y79xIFfBpsVQbqMwhvtu4j6qGEmT6DhDcbnlQU8kwTkf5dYopC2kBT +4atKKvWrfyoF2jDPSbwB0/ZztmRQtvE+Ve4+bGZREEy/0cviGmuGkzRXdfA/Ckl8 +4em9A01C8PzQ49psN+YGnl0OSiVXweHJzYnEy7/jep8ImHp8uXr2fT3sdreiUh9v +tv9j12Yy0AlgJp6TsgVPIpbS1CtZqF9vqojKAef3NxNZLjGKOdwlvlP+c0/A3xne +kubVCuGaVCrBvvZ3lOoqiDrkYjhaDADJoyQwNhU75Ah7fziJ1pjIyPUePYwJaOoc +b3ntUNAtLNy8EXTI0jhlJH4uo8aMi3eO52kNrRUScBtySATSCyB7k2gkdSfCnF03 +LUbDV2nTFK5NJ7+8rz/LNStu60nO5j1poVAPflbfz9mMNgb0wmncIyMr6w+Ixwpd +qSaFDC+2vJwwzhGmlg== +-----END CERTIFICATE----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning.key --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning.key Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning.pem Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIBATANBgkqhkiG9w0BAQUFADBZMSAwHgYDVQQDExdQdWJs +aWMgVHJ1c3RCcmlkZ2UgVGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBu +b3QgdHJ1c3QgdGhpczELMAkGA1UEBhMCREUwHhcNMTMwMTAxMDAwMDAwWhcNMTUx +MjMxMjM1OTU5WjBlMSwwKgYDVQQDEyNQdWJsaWMgVHJ1c3RCcmlkZ2UgY29kZXNp +Z25pbmcgdGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBub3QgdHJ1c3Qg +dGhpczELMAkGA1UEBhMCREUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDIz9IetAtdqJJ7aSfJcLmA9Mb4nxrqEJ5E6PMejDJZmmHNjyhCVp1qsLYmyC60 +m7qJ4OBENx0v2n5LiCUHJpJ4mzAklkWn1GffUkzWgQ2VHw5Nr44NWEwkUUa5/jT7 +Sxts2DWuaLz2r7oi6BUQpoRmQRPwwzFPONcCSw9iAvTU6oVI2jW1opEW3t10UwY3 +5/muryPsUz6y5VkBIc73VC0wByXoAruEPBBpMgOVw1+npOaJ1PL1XXQ/P6xziZo0 +Ab/tKvN6IpEHrNEGv1gScJt//pKKklvIyXm9UdIY9XpB6aauzthKpTFJXGYySlXx +bD1a5sq0i2sAK/p8RvErVWg3EfBlUrQryJxONPVqribczZIWcgKVEFfXjX1tQqiC +qRCgO4M6zhNIKLkAicp0DvYs8M4hIoPng98nqK6kSpfXR6Y4b9DU3yEktH7wGrwL +jKATVM2l2yTF17Pjxkr2tH0XWrChfS+oV6Qzm9JQ/vmLKz5piLKpt5SXuZny+j0Y +68ch709sVTuuPm4RAm5c5t0SCwEippClFpkZynYRsJVrjG9ZTrdvULxZao8GBzJx +Lb+tCaKP60BRoUuRfwGMKZbU6j6ujOCy5bZIoJaKgHgyAHXRuS4PIjY9K2BGM5vI +seA2GEdAJNmZPAQJE5rxkrsAH9n8QtmHucEqzCZVFcLuCwIDAQABo3AwbjAJBgNV +HRMEAjAAMB0GA1UdDgQWBBSMgUaKY3L65wH5M4il/gbHCeVm4TAfBgNVHSMEGDAW +gBTl/kZGRoa0cm82zW7CPn3yqk4MeTAOBgNVHQ8BAQEEBAMCAYAwEQYJYIZIAYb4 +QgEBBAQDAgAQMA0GCSqGSIb3DQEBBQUAA4ICAQAdmpf8k+ZKuhDvNwMCrf1JIZh3 +uJxlCHFke/ypsMT2E6p/GZpD/lLyRHbk7V5aEYdmBaK6Dem0KYhRuDclWscpQdXl +96wx1IDNueMkj5ZDmpBLFl/nqxlM9HfHo8YTE9dRgzJAR8+dFR8HyRSayKo+pz4L +FkNFT5Jtm9kKLIN+mSGKMBmpY4owfpeh7K6YyASoOHL9Zk8A0I7iZX8FB5KujrlG +WJahjSAyvLvy98XDCf9/SyX73F1ol5ycAb/du+G5VZFDEI8sv/7fIdTx/AUR30Ac +f3tqXZ4HwxWc0gofT0J2z/I4FZ/sT/1SNHReGNrG9GNn5bxjwpSXfc5A1bjhRfxd +x73xKEInjpgo6AXY7wfNk1V+2z7keVOpaDEZUOsd/x/C+L8FsUh2JJHZp/hKX6Co +AD///pxqNfvH5pPLUINC7VRUOTynUas7p9UvkPeJjqnWY6pmjeb4Fs6Z6vn0+Opy +HP1MjLL41a+U9VxuNb6SfRDoeT19pqK6ovT2gbc61OvTI0lE97ChC622rjnV0c/N +QYqkeTQG/IjPk0QFrYQxMqq6QKgds2nheYd4LyLGhk72pKWr28Hfj1ElcoTFFbWP +ndI+uZePkkCsVYNMXbIAIpqLb++1ftl+L+itqxTyq+0tPObIL3WG9rzBGz8X6WT0 +KIzi4KAn66e5/iWZng== +-----END CERTIFICATE----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning_root.key --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning_root.key Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/data/codesign/codesigning_root.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/tests/data/codesign/codesigning_root.pem Wed Jun 25 15:16:24 2014 +0200 @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIBATANBgkqhkiG9w0BAQUFADBZMSAwHgYDVQQDExdQdWJs +aWMgVHJ1c3RCcmlkZ2UgVGVzdDEoMCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBu +b3QgdHJ1c3QgdGhpczELMAkGA1UEBhMCREUwHhcNMTMwMTAxMDAwMDAwWhcNMTUx +MjMxMjM1OTU5WjBZMSAwHgYDVQQDExdQdWJsaWMgVHJ1c3RCcmlkZ2UgVGVzdDEo +MCYGA1UEChMfUHVibGljIHNlY3JldCBkbyBub3QgdHJ1c3QgdGhpczELMAkGA1UE +BhMCREUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDMAFKWbDfTe2wv +/k8jvUW4uy3kAk3unb/SSazSoRUOkAJHPBoNKJGtCPxBUreaydiJHB9d9GY62JzC +7tCmE3JUNnPmbMJTvmm44xwHUbx54BAlbyakPSTIlsQgx2K1JWGLV6+PPJ6Zbrd2 +V/81ngFkGgNX45gh3jsS0q9EPkOALoPd1bud2nGQ9lVdFoTD01Q/nd/iXGfFQygI +ZFHsQpr8m6jYItrPm3m9L6JEwb1defHQgxMWTdZ5VKjot80o6It8ddrOdb0TalE/ +JMlS8nh4QOfnztJlgDJCpkzLXs00K9R1F3PawYAYlDLrU6Bmx/C6pJECBpoZ9eLN +Obhak5bR24dDoAtHEiE7dI8n7SZ2TDrmR4sLBd0xxKgSYPyACHyX6zPYQGjUMWck +3IbDIsFjBeN4chfSyf8bAYvvstKlvv9APlMUaaVAz/EHCMz2pin9ayJ7dYgYQl9M +YmhfDuzSPMRX1HyBz56XS9X9STDZA08titLs8JE669jqFKl64wwbhyaU5LQwDOIB +Sd9/cJ7AB2ry9aC99vn5SknyYgkE+GpLuq+HsHBl898B37u4ayEAQjPgXSdwrjd4 +yXQQJa7lH4HxEqYrbV7yN+pbf9O7UhBS/20FGrnNrcFncYGSokCz8HSzSlTlnx7K +QHVzRNYYk5Q0AvUIQyMp4cPrF4VSHQIDAQABo1MwUTAPBgNVHRMECDAGAQEBAgEA +MB0GA1UdDgQWBBTl/kZGRoa0cm82zW7CPn3yqk4MeTAfBgNVHSMEGDAWgBTl/kZG +Roa0cm82zW7CPn3yqk4MeTANBgkqhkiG9w0BAQUFAAOCAgEAocyJF10oZa0Y20Sj +WyiQruMGW/Ag6AhjFd8akZXG3UGUHVj209op3nR3nrWRGovh8ZsLp51aNtjNaAIT +vtYRMSPE/W1GO+iVWOG6RI/XMTPokdWy4QDSteczJbMy4WxupjKZ09ID0eS5uaWC +4MYZOenBEpcAKO8cL3hAnahrxFGcDYCIYDSWJ1zjBBZphIu9IPHN8tgxmLIiQ7Ii +A/wm1lsvS7vTTR9jyGttxQOcjpyWDkvjemSJ2qFgbOfzF7CrtDxQPihiGo0DEuaP +8FdZFuHU6WDRGoxFhTAkYWXQiPVqSclwvMM6tcQTQ9t25OW9iT2Ykcss4PSY2Kx3 +x/xut8HRV1ikL7ROi0I1QbraOji7ro+AczsOmJx7KU1HAdMSun1bAdCyf7IKb/NK +UdqmohyUOOnCH5CupmSP4p8Az3Es7viSd/7qO6g3e3byU0XNHvCR0DFA8PA0bwu9 +h4g7mN4tRwI+hDkhO2q9uDokDf+iMN4o4w4w8DFrVTrGT/+/1Xo3JGTFnJafZX1b +nivzImON66SBsFiepeQ2vqQWSYfVn8MtGxviWSMODDbiHqILwK30nY0K+q/0K+T/ +Pw9r8vcoARIFMaUhIg8yXyqaEdWLgSSCBKwakR/CWpCYicFAa+Fwqetdf7Umsv5N +lftfVWONowED2z1t1jEwH4TG8cw= +-----END CERTIFICATE----- diff -r 39f03316f675 -r 129e611eaf50 ui/tests/mainwindowtest.cpp --- a/ui/tests/mainwindowtest.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/tests/mainwindowtest.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -23,10 +23,6 @@ emit closeCalled(); } -void MainWindowTest::testInvalidUpdate() { - // TODO -} - void MainWindowTest::testValidUpdate() { QSignalSpy closed(this, SIGNAL(closeCalled())); #ifdef Q_OS_WIN diff -r 39f03316f675 -r 129e611eaf50 ui/tests/mainwindowtest.h --- a/ui/tests/mainwindowtest.h Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/tests/mainwindowtest.h Wed Jun 25 15:16:24 2014 +0200 @@ -23,7 +23,6 @@ void closeApp(); private Q_SLOTS: - void testInvalidUpdate(); void testValidUpdate(); Q_SIGNALS: diff -r 39f03316f675 -r 129e611eaf50 ui/tests/windowsstoretest.cpp --- a/ui/tests/windowsstoretest.cpp Wed Jun 25 14:56:19 2014 +0200 +++ b/ui/tests/windowsstoretest.cpp Wed Jun 25 15:16:24 2014 +0200 @@ -14,7 +14,7 @@ #include void WindowsStoreTest::dumpContents() { - char pszNameString[256]; + wchar_t pszNameString[256]; PCCERT_CONTEXT pCert = NULL; qDebug() << "Currently in store: " ; while((pCert = CertEnumCertificatesInStore(testStore, pCert))) {