changeset 654:129e611eaf50

Merge branch trustbridge-refactor
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 25 Jun 2014 15:16:24 +0200
parents e41a2537b84d (diff) 39f03316f675 (current diff)
children 0ca15d937490
files ui/CMakeLists.txt ui/mainwindow.cpp ui/mainwindow.h
diffstat 55 files changed, 2692 insertions(+), 208 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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)
--- /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=<Prefix of your choice (default /usr)>
+    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 <magic nss folder> $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
--- 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;
         }
--- 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
--- 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 <stdlib.h>
 #include <limits.h>
 #include <errno.h>
+#include <pwd.h>
 
 #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
--- 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;
 }
--- 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})
--- /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 <polarssl/x509_crt.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <wintrust.h>
+#include <stdio.h>
+
+
+/** @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 */
--- /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 <stdbool.h>
+#include <stddef.h>
+
+#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 */
--- /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"
+.
--- 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 <string.h>
 
 #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;
     }
 
--- 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 */
--- 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 <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <strhelp.h>
+
+#include <certhelp.h>
+
+#include <polarssl/sha256.h>
 
 #ifdef WIN32
+# include <windows.h>
+# include "events.h"
+#else
+# include <syslog.h>
+#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);
+}
--- 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 <stdio.h>
+#include <stdbool.h>
+
+/** @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
--- 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
--- /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
+}
--- /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 <stdbool.h>
+
+#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
--- 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 <unistd.h>
 #include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
 #else
 #include <windows.h>
 #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;
--- /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
+}}}
--- /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 @@
+<?xml version="1.0"?>
+<testplan>
+    <meta>
+        <product-name>TrustBridge</product-name>
+        <product-version/>
+        <date/>
+        <tester/>
+        <test-date/>
+        <test-system/>
+        <test-version>0.1</test-version>
+        <test-duration/>
+        <comment/>
+    </meta>
+    <testsuite id="ts1" description="Verwaltungsanwendung">
+        <general-precondition/>
+        <test id="t1.1" description="Anwendung starten">
+            <precondition/>
+            <steps>
+                <step>Verwaltungsanwendung (trustbridge-admin) starten.</step>
+            </steps>
+            <results>
+                <result value="">Die Anwendung startet</result>
+            </results>
+        </test>
+        <test id="t1.2" description="Zertifikatsliste erstellen">
+            <precondition/>
+            <steps>
+                <step>Mehrere Zertifikate hinzufügen (z.B. aus ui/tests/data)</step>
+                <step>Liste erstellen</step>
+                <step>Signaturzertifikat angeben (z.B. ui/tests/data/testkey-priv.pem)</step>
+                <step>Ausgabeverzeichnis angeben</step>
+                <step>Liste erstellen</step>
+            </steps>
+            <results>
+                <result value="">Liste wurde erfolgreich im Ausgabeverzeichnis gespeichert</result>
+                <result value="">Liste wurde erfolgreich im Archivverzeichnis (~/.local share/BSI/trustbridge-admin/) gespeichert</result>
+            </results>
+        </test>
+        <test id="t1.3" description="Zertifikatsliste aktualisieren">
+            <precondition/>
+            <steps>
+                <step>Ein Zertifikat aus der Liste entfernen</step>
+                <step>Ein weiteres Zertifikate hinzufügen (z.B. aus ui/tests/data)</step>
+                <step>Liste erstellen (Signaturzertifikat und Ausgabeverzeichnis unverändert lassen)</step>
+                <step>Liste erstellen</step>
+            </steps>
+            <results>
+                <result value="">Liste wurde erfolgreich im Ausgabeverzeichnis gespeichert</result>
+                <result value="">Liste wurde erfolgreich im Archivverzeichnis (~/.local share/BSI/trustbridge-admin/) gespeichert</result>
+            </results>
+        </test>
+        <test id="t1.4" description="Letzte Zertifikatsliste automatisch laden">
+            <precondition/>
+            <steps>
+                <step>Verwaltungsanwendung neustarten</step>
+            </steps>
+            <results>
+                <result value="">Die zuletzt erstellte Zertifikatsliste wird angezeigt</result>
+            </results>
+        </test>
+        <test id="t1.5" description="Installationspaket erzeugen">
+            <precondition/>
+            <steps>
+                <step>Installationspaket erstellen...</step>
+                <step>Verzeichnis des Binärpakets angeben (enthält meta.ini)</step>
+                <step>Code-Signing-Zertifikat angeben (z.B. ui/tests/data/codesign/codesigning.pem)</step>
+                <step>Ausgabeverzeichnis angeben</step>
+                <step>Installationspaket erzeugen</step>
+            </steps>
+            <results>
+                <result>Installationspaket für Windows (NSIS-Installer) wurde im Ausgabeverzeichnis erstellt.</result>
+                <result>Installationspaket für Ubuntu wurde im Ausgabeverzeichnis erstellt.</result>
+            </results>
+        </test>
+        <test id="t1.6" description="Anwendung beenden">
+            <precondition/>
+            <steps>
+                <step>Verwaltungsanwendung beenden.</step>
+            </steps>
+            <results>
+                <result value="">Die Anwendung schließt sich</result>
+            </results>
+        </test>
+    </testsuite>
+    <testsuite id="ts2" description="Clientanwendung">
+        <general-precondition>Der TrustBridge Client Installer liegt vor.</general-precondition>
+        <test id="t2.1" description="Installation unter Windows (mit Administratorrechten)">
+            <precondition>Nutzer besitzt Adminstratorrechte.</precondition>
+            <steps>
+                <step>NSIS-Installer ausführen (mit Vorbelegung)</step>
+            </steps>
+            <results>
+                <result>Anwendung startet nach Installation automatisch.</result>
+                <result>Eintrag im Startmenü ist vorhanden</result>
+            </results>
+        </test>
+        <test id="t2.2" description="Installation unter Windows (ohne Administratorrechten)">
+            <precondition>Nutzer besitzt keine Adminstratorrechte.</precondition>
+            <steps>
+                <step>NSIS-Installer ausführen (mit Vorbelegung)</step>
+            </steps>
+            <results>
+                <result>Anwendung startet nach Installation automatisch.</result>
+                <result>Eintrag im Startmenü ist vorhanden</result>
+            </results>
+        </test>
+    </testsuite>
+</testplan>
--- 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" \
--- 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
 
--- 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
--- 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);
--- 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();
--- 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 <QStyle>
 #include <QApplication>
 #include <QMessageBox>
+#include <QTemporaryDir>
+
+/* 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)
--- 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 <QLineEdit>
 #include <QProcess>
 #include <QProgressDialog>
+#include <QDir>
 /**
  * @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);
--- 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);
--- 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"
--- 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();
--- 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 @@
         <translation type="vanished">TrustBridge ist ein sicherer Wurzelzertifikatsinstaller für Windows und Linux.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="50"/>
+        <location filename="../aboutdialog.cpp" line="53"/>
         <source>TrustBridge is a root certificate installer for Windows and Linux.</source>
         <translation>TrustBridge ist ein Wurzelzertifikatsinstaller für Windows und Linux.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="52"/>
+        <location filename="../aboutdialog.cpp" line="58"/>
         <source>The root certificate lists are managed by the German &lt;a href=&quot;https://www.bsi.bund.de&quot;&gt;Federal Office for Information Security (BSI)&lt;/a&gt;.
 
 </source>
         <translation>Die Liste der Wurzelzertifikate wird vom &lt;a href=&quot;https://www.bsi.bund.de&quot;&gt;Bundesamt für Sicherheit in der Informationstechnik (BSI)&lt;/a&gt; verwaltet.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="55"/>
+        <location filename="../aboutdialog.cpp" line="64"/>
         <source>The software was developed by the companies &lt;a href=&quot;http://www.intevation.de&quot;&gt;Intevation GmbH&lt;/a&gt; and  &lt;a href=&quot;http://www.dn-systems.de&quot;&gt;DN-Systems GmbH&lt;/a&gt;, &lt;br&gt; contracted by the German Federal Office for Information Security (BSI).
 
 </source>
         <translation>Die Software wurde entwickelt von den Unternehmen &lt;a href=&quot;http://www.intevation.net&quot;&gt;Intevation GmbH&lt;/a&gt; und  &lt;a href=&quot;http://www.dn-systems.com&quot;&gt;DN-Systems GmbH&lt;/a&gt;, &lt;br&gt; beauftragt durch das Bundesamt für Sicherheit in der Informationstechnik (BSI).</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="59"/>
+        <location filename="../aboutdialog.cpp" line="71"/>
         <source>TrustBridge is Free Software licensed under GNU GPL v2+.
 
 Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik</source>
@@ -46,7 +46,7 @@
 Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik (BSI)</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="73"/>
+        <location filename="../aboutdialog.cpp" line="88"/>
         <source>Close</source>
         <translation>Schließen</translation>
     </message>
@@ -54,78 +54,139 @@
 <context>
     <name>AdministratorWindow</name>
     <message>
-        <location filename="../administratorwindow.cpp" line="33"/>
-        <location filename="../administratorwindow.cpp" line="101"/>
+        <location filename="../administratorwindow.cpp" line="34"/>
+        <location filename="../administratorwindow.cpp" line="102"/>
         <source>TrustBridge Administration</source>
         <translation>TrustBridge Verwaltung</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="51"/>
+        <location filename="../administratorwindow.cpp" line="52"/>
         <source>Menu</source>
         <translation>Menü</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="53"/>
+        <location filename="../administratorwindow.cpp" line="54"/>
         <source>Create installer ...</source>
         <translation>Installationspaket erstellen ...</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="54"/>
+        <location filename="../administratorwindow.cpp" line="55"/>
         <source>About TrustBridge</source>
         <translation>Ãœber TrustBridge</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="56"/>
+        <location filename="../administratorwindow.cpp" line="57"/>
         <source>Quit</source>
         <translation>Beenden</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="77"/>
+        <location filename="../administratorwindow.cpp" line="78"/>
         <source>All managed root certificates of the certificate list: </source>
         <translatorcomment>The english original should be improved</translatorcomment>
         <translation>In der Liste enthaltene Zertifikate:</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="143"/>
+        <location filename="../administratorwindow.cpp" line="144"/>
         <source>Select certificate list file</source>
         <translation>Zertifikatsliste auswählen</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="146"/>
+        <location filename="../administratorwindow.cpp" line="150"/>
+        <location filename="../administratorwindow.cpp" line="234"/>
+        <location filename="../administratorwindow.cpp" line="244"/>
         <source>Error!</source>
         <translation>Fehler!</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="146"/>
+        <location filename="../administratorwindow.cpp" line="150"/>
         <source>Failed to load the certificate list.</source>
         <translation>Fehler beim Laden der Zertifikatsliste.</translation>
     </message>
     <message>
+        <location filename="../administratorwindow.cpp" line="234"/>
+        <source>Failed to open log file: </source>
+        <translation>Fehler beim Öffnen der Log-Datei:</translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="235"/>
+        <location filename="../administratorwindow.cpp" line="245"/>
+        <source> Changes are not logged!</source>
+        <translation> Änderungen wurden nicht geloggt!</translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="244"/>
+        <source>Failed to write log file: </source>
+        <translation>Fehler beim Schreiben der Log-Datei: </translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="262"/>
+        <source> new certificatelist </source>
+        <translation> neue Zertifikatsliste </translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="264"/>
+        <source> based on list from </source>
+        <translation> basiert auf der Liste vom </translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="267"/>
+        <source>signing certificate: 
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="268"/>
+        <source>new certificates:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../administratorwindow.cpp" line="282"/>
+        <source>certificates marked to remove:
+</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <source>signing certificate: 
+</source>
+        <translation type="obsolete">signiertes Zertifikat: </translation>
+    </message>
+    <message>
+        <source>new certificates:
+</source>
+        <translation type="obsolete">neues Zertifikat:</translation>
+    </message>
+    <message>
+        <source>certificates marked to remove:
+</source>
+        <translation type="obsolete">Zertifikate als gelöscht markiert:</translation>
+    </message>
+    <message>
         <source>All managed root certificates of the certificate list:</source>
         <translation type="vanished">Alle verwalteten Wurzelzertifikate der Zertifikatsliste:</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="103"/>
+        <location filename="../administratorwindow.cpp" line="104"/>
         <source>Management application of the BSI certificate installer</source>
         <translation>Verwaltungsanwendung des BSI-Zertifikatsinstallers</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="113"/>
+        <location filename="../administratorwindow.cpp" line="114"/>
         <source>Save list</source>
         <translation>Liste speichern</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="115"/>
+        <location filename="../administratorwindow.cpp" line="116"/>
         <source>Load list</source>
         <translation>Liste laden</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="117"/>
+        <location filename="../administratorwindow.cpp" line="118"/>
         <source>Add certificate</source>
         <translation>Zertifikat hinzufügen</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="119"/>
+        <location filename="../administratorwindow.cpp" line="120"/>
         <source>Remove certificate</source>
         <translation>Zertifikat entfernen</translation>
     </message>
@@ -134,12 +195,45 @@
         <translation type="vanished">Zertifikatslistendatei auswählen</translation>
     </message>
     <message>
-        <location filename="../administratorwindow.cpp" line="163"/>
+        <location filename="../administratorwindow.cpp" line="171"/>
         <source>Select certificate</source>
         <translation>Zertifikat auswählen</translation>
     </message>
 </context>
 <context>
+    <name>CertificateDiffDialog</name>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="22"/>
+        <source>TrustBridge - List changes</source>
+        <translation>TrustBridge - Listenänderungen</translation>
+    </message>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="33"/>
+        <source>The following certificates are changed:</source>
+        <translation>Die folgenden Zertifikate wurden geändert:</translation>
+    </message>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="41"/>
+        <source>New</source>
+        <translation>Neu</translation>
+    </message>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="41"/>
+        <source>Remove</source>
+        <translation>Entfernen</translation>
+    </message>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="50"/>
+        <source>Ok</source>
+        <translation>Ok</translation>
+    </message>
+    <message>
+        <location filename="../certificatediffdialog.cpp" line="51"/>
+        <source>Cancel</source>
+        <translation>Abbrechen</translation>
+    </message>
+</context>
+<context>
     <name>CertificateTabelModel</name>
     <message>
         <location filename="../certificatetablemodel.cpp" line="16"/>
@@ -313,8 +407,8 @@
 <context>
     <name>CreateInstallerDialog</name>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="28"/>
-        <location filename="../createinstallerdialog.cpp" line="53"/>
+        <location filename="../createinstallerdialog.cpp" line="43"/>
+        <location filename="../createinstallerdialog.cpp" line="68"/>
         <source>Create binary installer</source>
         <translation>Installationspaket erstellen</translation>
     </message>
@@ -331,93 +425,126 @@
         <translation type="vanished">Code Signing Zertifikat auswählen (privater Schlüssel):</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="55"/>
+        <location filename="../createinstallerdialog.cpp" line="70"/>
         <source>Create and sign a TrustBridge binary installer.</source>
         <translation>Erzeugt und signiert ein TrustBridge-Installationspaket.</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="66"/>
+        <location filename="../createinstallerdialog.cpp" line="81"/>
         <source>Select binary folder:</source>
         <translation>Binärverzeichnis auswählen:</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="67"/>
+        <location filename="../createinstallerdialog.cpp" line="82"/>
         <source>Select code signing certificate:</source>
         <translation>Code-Signing-Zertifikat auswählen:</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="68"/>
+        <location filename="../createinstallerdialog.cpp" line="83"/>
         <source>Select output folder:</source>
         <translation>Ausgabeverzeichnis auswählen:</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="97"/>
+        <location filename="../createinstallerdialog.cpp" line="112"/>
         <source>Create installer</source>
         <translation>Installationspaket erzeugen</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="99"/>
+        <location filename="../createinstallerdialog.cpp" line="114"/>
         <source>Cancel</source>
         <translation>Abbrechen</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="119"/>
+        <location filename="../createinstallerdialog.cpp" line="208"/>
         <source>Creating installer package...</source>
         <translation>Installationspaket wird erstellt...</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="131"/>
+        <location filename="../createinstallerdialog.cpp" line="145"/>
         <source>Select certificate</source>
         <translation>Zertifikat auswählen</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="142"/>
+        <location filename="../createinstallerdialog.cpp" line="156"/>
         <source>Select binary folder</source>
         <translation>Binärverzeichnis auswählen</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="160"/>
+        <location filename="../createinstallerdialog.cpp" line="174"/>
         <source>Error!</source>
         <translation>Fehler!</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="165"/>
+        <location filename="../createinstallerdialog.cpp" line="183"/>
         <source>Created installer in %1.</source>
         <translation>Installationspaket erstellt in %1.</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="184"/>
+        <location filename="../createinstallerdialog.cpp" line="186"/>
+        <source>Signing installer package...</source>
+        <translation>Installationspaket signieren...</translation>
+    </message>
+    <message>
+        <location filename="../createinstallerdialog.cpp" line="188"/>
+        <source>Failed to sign installer package.</source>
+        <translation>Fehler beim Signieren des Installationspakets.</translation>
+    </message>
+    <message>
+        <location filename="../createinstallerdialog.cpp" line="212"/>
         <source>Please select an existing input folder.</source>
         <translation>Bitte wählen Sie ein existierendes Eingabeverzeichnis.</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="188"/>
+        <location filename="../createinstallerdialog.cpp" line="216"/>
         <source>Please select a codesigning certificate.</source>
         <translation>Bitte wählen Sie ein Code-Signing-Zertifikat.</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="192"/>
+        <location filename="../createinstallerdialog.cpp" line="220"/>
         <source>Please select a output folder.</source>
         <translation>Bitte wählen Sie ein Ausgabeverzeichnis.</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="199"/>
+        <location filename="../createinstallerdialog.cpp" line="227"/>
         <source>Folder %1 does not appear to contain a meta.ini</source>
         <translation>Das Verzeichnis %1 enthält keine meta.ini Datei</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="240"/>
+        <location filename="../createinstallerdialog.cpp" line="239"/>
+        <source>Creating NSIS package...</source>
+        <translation>NSIS-Paket wird erstellt...</translation>
+    </message>
+    <message>
+        <location filename="../createinstallerdialog.cpp" line="279"/>
         <source>Failed to start makensis.
 Please ensure that makensis is installed and in your PATH variable.</source>
         <translation>Fehler beim Starten von makensis.
 Bitte versichern Sie sich, dass makensis korrekt installiert und in der PATH-Variable enthalten ist.</translation>
     </message>
     <message>
+        <location filename="../createinstallerdialog.cpp" line="335"/>
+        <source>Signing binaries...</source>
+        <translation>Binärpakete werden signiert...</translation>
+    </message>
+    <message>
+        <location filename="../createinstallerdialog.cpp" line="345"/>
+        <source>Failed to copy binaries to temporary location.</source>
+        <translation>Fehler beim Kopieren der Binärdaten in temporären Ort.</translation>
+    </message>
+    <message>
+        <location filename="../createinstallerdialog.cpp" line="351"/>
+        <source>Failed to sign binaries with osslsigncode.
+Please check that %1 is a valid code signing certificate and thatosslsigncode can be found in the PATH.</source>
+        <translatorcomment>TODO: missing blank in EN string</translatorcomment>
+        <translation>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.</translation>
+    </message>
+    <message>
         <source>Select source archive</source>
         <translation type="vanished">Archiv auswählen</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="152"/>
+        <location filename="../createinstallerdialog.cpp" line="166"/>
         <source>Select target location</source>
         <translation>Zielort auswählen</translation>
     </message>
@@ -425,22 +552,22 @@
 <context>
     <name>FinishedDialog</name>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="259"/>
+        <location filename="../createinstallerdialog.cpp" line="377"/>
         <source>Success!</source>
         <translation>Erfolgreich!</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="263"/>
+        <location filename="../createinstallerdialog.cpp" line="381"/>
         <source>Error!</source>
         <translation>Fehler!</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="271"/>
+        <location filename="../createinstallerdialog.cpp" line="389"/>
         <source>Details</source>
         <translation>Details</translation>
     </message>
     <message>
-        <location filename="../createinstallerdialog.cpp" line="275"/>
+        <location filename="../createinstallerdialog.cpp" line="393"/>
         <source>OK</source>
         <translation>OK</translation>
     </message>
--- 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 @@
         <translation type="vanished">TrustBridge ist eine sicherer Wurzelzertifikatsinstaller für Windows und Linux.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="50"/>
+        <location filename="../aboutdialog.cpp" line="53"/>
         <source>TrustBridge is a root certificate installer for Windows and Linux.</source>
-        <translation type="unfinished">TrustBridge ist eine Wurzelzertifikatsinstaller für Windows und Linux.</translation>
+        <translation>TrustBridge ist eine Wurzelzertifikatsinstaller für Windows und Linux.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="52"/>
+        <location filename="../aboutdialog.cpp" line="58"/>
         <source>The root certificate lists are managed by the German &lt;a href=&quot;https://www.bsi.bund.de&quot;&gt;Federal Office for Information Security (BSI)&lt;/a&gt;.
 
 </source>
         <translation>Die Liste der Wurzelzertifikate wird vom &lt;a href=&quot;https://www.bsi.bund.de&quot;&gt;Bundesamt für Sicherheit in der Informationstechnik (BSI)&lt;/a&gt; verwaltet.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="55"/>
+        <location filename="../aboutdialog.cpp" line="64"/>
         <source>The software was developed by the companies &lt;a href=&quot;http://www.intevation.de&quot;&gt;Intevation GmbH&lt;/a&gt; and  &lt;a href=&quot;http://www.dn-systems.de&quot;&gt;DN-Systems GmbH&lt;/a&gt;, &lt;br&gt; contracted by the German Federal Office for Information Security (BSI).
 
 </source>
         <translation>Die Liste der Wurzelzertifikate wird vom &lt;a href=&quot;https://www.bsi.bund.de&quot;&gt;Bundesamt für Sicherheit in der Informationstechnik (BSI)&lt;/a&gt; verwaltet.</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="59"/>
+        <location filename="../aboutdialog.cpp" line="71"/>
         <source>TrustBridge is Free Software licensed under GNU GPL v2+.
 
 Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik</source>
@@ -46,7 +46,7 @@
 Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik (BSI)</translation>
     </message>
     <message>
-        <location filename="../aboutdialog.cpp" line="73"/>
+        <location filename="../aboutdialog.cpp" line="88"/>
         <source>Close</source>
         <translation>Schließen</translation>
     </message>
@@ -116,7 +116,7 @@
 <context>
     <name>MainWindow</name>
     <message>
-        <location filename="../mainwindow.cpp" line="178"/>
+        <location filename="../mainwindow.cpp" line="228"/>
         <source>An updated certificate list is available. Click here to install.</source>
         <translation>Eine aktualisierte Zertifikatsliste ist verfügbar. Klicken Sie hier zum Installieren.</translation>
     </message>
@@ -134,34 +134,34 @@
         <translation type="vanished">Möchten Sie die neue Version installieren?</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="334"/>
+        <location filename="../mainwindow.cpp" line="399"/>
         <source>Check for Updates</source>
         <translation>Aktualisierungen prüfen</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="336"/>
-        <location filename="../mainwindow.cpp" line="369"/>
-        <location filename="../mainwindow.cpp" line="449"/>
+        <location filename="../mainwindow.cpp" line="401"/>
+        <location filename="../mainwindow.cpp" line="434"/>
+        <location filename="../mainwindow.cpp" line="514"/>
         <source>Quit</source>
         <translation>Beenden</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="354"/>
+        <location filename="../mainwindow.cpp" line="419"/>
         <source>TrustBridge</source>
         <translation>TrustBridge</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="362"/>
+        <location filename="../mainwindow.cpp" line="427"/>
         <source>Menu</source>
         <translation>Menü</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="364"/>
+        <location filename="../mainwindow.cpp" line="429"/>
         <source>Force Update</source>
         <translation>Aktualisierung erzwingen</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="425"/>
+        <location filename="../mainwindow.cpp" line="490"/>
         <source>Settings</source>
         <translation>Einstellungen</translation>
     </message>
@@ -170,131 +170,144 @@
         <translation type="vanished">Statusdialog</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="186"/>
-        <source>&lt;h3&gt;An update for %1 is available.&lt;/h3&gt;
+        <location filename="../mainwindow.cpp" line="236"/>
+        <source>An update for %1 is available.
 Click here to download and install the update.</source>
-        <translation type="unfinished"></translation>
+        <translation>Eine Aktualisierung für %1 ist verfügbar.
+Hier klicken, um Download und Installation zu starten.</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="366"/>
+        <location filename="../mainwindow.cpp" line="431"/>
         <source>Help</source>
         <translation>Hilfe</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="367"/>
+        <location filename="../mainwindow.cpp" line="432"/>
         <source>About</source>
         <translatorcomment>&quot;TrustBridge&quot; ergänzen</translatorcomment>
         <translation>Ãœber TrustBridge</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="396"/>
+        <location filename="../mainwindow.cpp" line="461"/>
         <source>Managed Certificates</source>
         <translation>Verwaltete Zertifikate</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="402"/>
-        <location filename="../mainwindow.cpp" line="540"/>
-        <location filename="../mainwindow.cpp" line="570"/>
+        <location filename="../mainwindow.cpp" line="467"/>
+        <location filename="../mainwindow.cpp" line="605"/>
+        <location filename="../mainwindow.cpp" line="635"/>
         <source>Current List Date: %1</source>
         <translation>Datum der aktuellen Liste: %1</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="426"/>
+        <location filename="../mainwindow.cpp" line="491"/>
         <source>Autoupdate</source>
         <translation>Automatische Aktualisierung</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="427"/>
+        <location filename="../mainwindow.cpp" line="492"/>
         <source>Autostart</source>
         <translation>Start der Anwendung bei Systemstart</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="445"/>
+        <location filename="../mainwindow.cpp" line="510"/>
         <source>Install selected</source>
         <translation>Jetzt installieren</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="466"/>
+        <location filename="../mainwindow.cpp" line="531"/>
         <source>Details</source>
         <translation>Details</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="467"/>
+        <location filename="../mainwindow.cpp" line="532"/>
         <source>Subject Common Name:</source>
         <translation>Inhaber CN:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="468"/>
+        <location filename="../mainwindow.cpp" line="533"/>
         <source>Subject Organisation:</source>
         <translation>Inhaber Organisation:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="469"/>
+        <location filename="../mainwindow.cpp" line="534"/>
         <source>Issuer Common Name:</source>
         <translation>Aussteller CN:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="470"/>
+        <location filename="../mainwindow.cpp" line="535"/>
         <source>Issuer Organisation:</source>
         <translation>Aussteller Organisation:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="471"/>
+        <location filename="../mainwindow.cpp" line="536"/>
         <source>Valid from:</source>
         <translation>Gültig ab:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="472"/>
+        <location filename="../mainwindow.cpp" line="537"/>
         <source>Valid to:</source>
         <translation>Gültig bis:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="473"/>
+        <location filename="../mainwindow.cpp" line="538"/>
         <source>Fingerprint:</source>
         <translation>Fingerprint:</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="572"/>
+        <location filename="../mainwindow.cpp" line="637"/>
         <source>New List Date: %1</source>
         <translation>Datum der neuen Liste: %1</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="577"/>
+        <location filename="../mainwindow.cpp" line="642"/>
         <source>New certificates to install</source>
         <translation>Neu zu installierende Zertifikate</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="584"/>
+        <location filename="../mainwindow.cpp" line="649"/>
         <source>New certificates to remove</source>
         <translation>Neu zu löschende Zertifikate</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="591"/>
+        <location filename="../mainwindow.cpp" line="656"/>
         <source>Old certificates to install</source>
         <translation>Bisher installierte Zertifikate</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="598"/>
+        <location filename="../mainwindow.cpp" line="663"/>
         <source>Old certificates to remove</source>
         <translation>Bisher gelöschte Zertifikate</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="673"/>
+        <location filename="../mainwindow.cpp" line="738"/>
         <source>Error executing update</source>
         <translation>Fehler bei der Aktualisierung</translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="718"/>
+        <location filename="../mainwindow.cpp" line="783"/>
         <source>Installing certificates...</source>
         <translation>Zertifikate werden installiert...</translation>
     </message>
 </context>
 <context>
+    <name>ProcessWaitDialog</name>
+    <message>
+        <location filename="../processwaitdialog.cpp" line="23"/>
+        <source>Applications need to be closed.</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../processwaitdialog.cpp" line="26"/>
+        <source>Close all running firefox and thunderbird instances to continue installation!</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
     <name>QObject</name>
     <message>
-        <location filename="../main.cpp" line="72"/>
         <source>Couldn&apos;t detect any system tray on this system. This software can only be used in a desktop environment.</source>
-        <translation>Es konnte kein SystemTray auf diesem System gefunden werden. Diese Software kann nur in einer Desktopumgebung verwendet werden.</translation>
+        <translation type="vanished">Es konnte kein SystemTray auf diesem System gefunden werden. Diese Software kann nur in einer Desktopumgebung verwendet werden.</translation>
     </message>
 </context>
 <context>
--- 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 <QApplication>
 #include <QSystemTrayIcon>
@@ -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 */
--- 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 <QButtonGroup>
 #include <QToolButton>
 
+#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<LPCWSTR> (filePath.utf16());
+    shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (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<int> 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
--- 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();
--- /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 <QList>
+#include <QString>
+
+/**
+ * @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<int> 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
--- /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<int> ProcessHelp::getProcessesIdForName(const QString &processName) {
+    // TODO
+    Q_UNUSED(processName);
+    return QList<int>();
+}
+
+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 */
--- /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 <windows.h>
+#include <tlhelp32.h>
+#include <psapi.h>
+#include <unistd.h>
+
+#include <QDebug>
+
+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<PTOKEN_USER>(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<int> ProcessHelp::getProcessesIdForName(const QString &processName)
+{
+    HANDLE h;
+    PROCESSENTRY32 pe32;
+    QList <int> 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<int> 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<int> 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
+
--- /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 <QHBoxLayout>
+#include <QListWidget>
+#include <QTimer>
+#include <QList>
+#include <QLabel>
+#include <QApplication>
+
+#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<int> 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()));
+}
--- /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 <QDialog>
+#include <QStringList>
+
+/** @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
--- 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)
 {
--- 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()
--- /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 <QTest>
+
+#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);
--- /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 <QObject>
+
+class BinVerifyTest: public QObject
+{
+  Q_OBJECT
+
+private Q_SLOTS:
+  void testNoSignature();
+  void testMiscErrors();
+  void testValidBinary();
+  void testOtherKey();
+  void testOtherCert();
+  void testInvalidSig();
+};
+#endif
+
--- 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
--- /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-----
+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
+-----END RSA PRIVATE KEY-----
--- /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-----
--- /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-----
--- /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-----
--- /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-----
--- /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-----
--- 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
--- 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:
--- 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 <QTest>
 
 void WindowsStoreTest::dumpContents() {
-    char pszNameString[256];
+    wchar_t pszNameString[256];
     PCCERT_CONTEXT pCert = NULL;
     qDebug() << "Currently in store: " ;
     while((pCert = CertEnumCertificatesInStore(testStore, pCert))) {

http://wald.intevation.org/projects/trustbridge/