changeset 1288:265583011f24

(issue123) Add possibility to open native certificate dialog This is currently only implemented for windows.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 29 Sep 2014 13:12:58 +0200
parents d3d66d43365f
children 34c92dbfee7e
files cinst/CMakeLists.txt cinst/windowsstore.c common/certhelp.c common/certhelp.h ui/certificate.cpp ui/certificate.h ui/certificateitemwidget.cpp ui/certificateitemwidget.h
diffstat 8 files changed, 165 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/cinst/CMakeLists.txt	Mon Sep 29 13:02:41 2014 +0200
+++ b/cinst/CMakeLists.txt	Mon Sep 29 13:12:58 2014 +0200
@@ -30,6 +30,7 @@
 
 if (WIN32)
    set(WIN_EXTRA_LIBS -lcrypt32 -luserenv -lshell32)
+   set(WIN_EXTRA_LIBS_NSS -lcrypt32)
 endif(WIN32)
 
 target_link_libraries(trustbridge-certificate-installer
@@ -87,7 +88,8 @@
       trustbridge_common
       ${POLARSSL_LIBRARIES}
       ${NSS_LIBRARIES}
-      ${PROFILING_LIBS})
+      ${PROFILING_LIBS}
+      ${WIN_EXTRA_LIBS_NSS})
    set_target_properties(trustbridge-nss-installer PROPERTIES COMPILE_FLAGS "-std=c99")
    install(TARGETS trustbridge-nss-installer DESTINATION bin)
 
--- a/cinst/windowsstore.c	Mon Sep 29 13:02:41 2014 +0200
+++ b/cinst/windowsstore.c	Mon Sep 29 13:12:58 2014 +0200
@@ -15,43 +15,7 @@
 #include "strhelp.h"
 #include "logging.h"
 #include "util.h"
-
-static PCCERT_CONTEXT
-b64_to_cert_context(char *b64_data, size_t b64_size)
-{
-  size_t buf_size = 0;
-  char *buf = NULL;
-  PCCERT_CONTEXT pCert = NULL;
-  int ret = -1;
-
-  ret = str_base64_decode (&buf, &buf_size, b64_data, b64_size);
-
-  if (ret != 0)
-    {
-      ERRORPRINTF ("decoding certificate failed\n");
-      return NULL;
-    }
-
-  pCert = CertCreateContext (CERT_STORE_CERTIFICATE_CONTEXT,
-                             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
-                             (const PBYTE) buf,
-                             (DWORD) buf_size,
-                             0,
-                             NULL);
-  free (buf); /* Windows has a copy */
-
-  if (pCert == NULL)
-    {
-      char *error = getLastErrorMsg();
-      if (error)
-        {
-          ERRORPRINTF ("Failed to create cert context: %s \n", error);
-          free (error);
-        }
-      return NULL;
-    }
-  return pCert;
-}
+#include "certhelp.h"
 
 void
 do_remove(HCERTSTORE hStore, char **to_remove)
--- a/common/certhelp.c	Mon Sep 29 13:02:41 2014 +0200
+++ b/common/certhelp.c	Mon Sep 29 13:12:58 2014 +0200
@@ -50,3 +50,42 @@
     }
   return str;
 }
+
+#ifdef WIN32
+PCCERT_CONTEXT
+b64_to_cert_context(char *b64_data, size_t b64_size)
+{
+  size_t buf_size = 0;
+  char *buf = NULL;
+  PCCERT_CONTEXT pCert = NULL;
+  int ret = -1;
+
+  ret = str_base64_decode (&buf, &buf_size, b64_data, b64_size);
+
+  if (ret != 0)
+    {
+      ERRORPRINTF ("decoding certificate failed\n");
+      return NULL;
+    }
+
+  pCert = CertCreateContext (CERT_STORE_CERTIFICATE_CONTEXT,
+                             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+                             (const PBYTE) buf,
+                             (DWORD) buf_size,
+                             0,
+                             NULL);
+  free (buf); /* Windows has a copy */
+
+  if (pCert == NULL)
+    {
+      char *error = getLastErrorMsg();
+      if (error)
+        {
+          ERRORPRINTF ("Failed to create cert context: %s \n", error);
+          free (error);
+        }
+      return NULL;
+    }
+  return pCert;
+}
+#endif
--- a/common/certhelp.h	Mon Sep 29 13:02:41 2014 +0200
+++ b/common/certhelp.h	Mon Sep 29 13:12:58 2014 +0200
@@ -24,6 +24,12 @@
 #define CERT_OID_O      (unsigned char *)OID_AT_ORGANIZATION "\0"
 #define CERT_OID_OU     (unsigned char *)OID_AT_ORG_UNIT "\0"
 #define CERT_OID_SN     (unsigned char *)OID_AT_SERIAL_NUMBER "\0"
+
+#ifdef WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -58,6 +64,23 @@
  */
 char *x509_parse_subject(unsigned char *derdata, size_t derlen,
                          unsigned char *oid);
+
+#ifdef WIN32
+/**
+ * @brief Parse a X509 ASN encoded base64 encoded certificate.
+ *
+ * This function creates a Windows cert contect for the certificate
+ * encoded in b64_data. The new certificate has to be freed with
+ * CertFreeCertificateContext.
+ *
+ * @param[in] b64_data pointer to the certificate data.
+ * @param[in] b64_size sizeof the the data. (Without terminating \0)
+ *
+ * @returns NULL on error.
+ */
+PCCERT_CONTEXT b64_to_cert_context(char *b64_data, size_t b64_size);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
--- a/ui/certificate.cpp	Mon Sep 29 13:02:41 2014 +0200
+++ b/ui/certificate.cpp	Mon Sep 29 13:12:58 2014 +0200
@@ -16,6 +16,10 @@
 #include "certhelp.h"
 #include "listutil.h"
 
+#ifdef WIN32
+#include <cryptuiapi.h>
+#endif
+
 /* Qt wrapper around certhelp functions. */
 QString getX509Value(x509_name *namebuf, unsigned char *oid) {
     QString retval;
@@ -196,3 +200,64 @@
         mBaseLine.replace(0, 1, "R");
     }
 }
+
+#ifdef WIN32
+bool Certificate::showNativeUI(void *parent)
+{
+    /* Cut of the first two chars (e.g. I: and decode) */
+    bool retval = false;
+    QByteArray pemData = QByteArray(
+            mBaseLine.right(mBaseLine.size() - 2).toLatin1());
+    PCCERT_CONTEXT pCert = b64_to_cert_context (pemData.data(), pemData.size());
+    typedef BOOL (CALLBACK* LPFNVIEWDLG)(DWORD,const void *,HWND,LPCWSTR,DWORD,void *);
+    LPFNVIEWDLG funcPtr;
+
+    /* CryptUIDlgViewContext is not part of mingw 3.1.0
+     * so we workaround this by geting the process address dynamically. */
+    HMODULE hmod = LoadLibraryW(L"cryptui");
+
+    if (!hmod) {
+        qDebug() << "Failed to open Cryptui.dll";
+        goto done;
+    }
+
+    funcPtr = (LPFNVIEWDLG) GetProcAddress (hmod, "CryptUIDlgViewContext");
+    if (!funcPtr) {
+        qDebug() << "Failed to find Address of CryptUIDlgViewContext";
+        goto done;
+    }
+
+    if (pCert == NULL) {
+        qDebug() << "Failed to parse certificate.";
+        goto done;
+    }
+
+    if (!funcPtr(CERT_STORE_CERTIFICATE_CONTEXT,
+                 pCert,
+                 (HWND) parent,
+                 NULL, // Default Title
+                 0,
+                 NULL)) {
+        qDebug() << "Failed to view certificate.";
+        retval = false;
+        goto done;
+    }
+
+    retval = true;
+done:
+
+    if (pCert) {
+        CertFreeCertificateContext(pCert);
+    }
+    if (hmod) {
+        FreeLibrary(hmod);
+    }
+    return retval;
+}
+#else
+bool Certificate::showNativeUI(void *parent)
+{
+    qDebug() << "Not implemented.";
+    return false;
+}
+#endif
--- a/ui/certificate.h	Mon Sep 29 13:02:41 2014 +0200
+++ b/ui/certificate.h	Mon Sep 29 13:12:58 2014 +0200
@@ -161,6 +161,19 @@
     friend inline bool operator==(const Certificate& lhs, const Certificate& rhs) {
         return lhs.base64Line() == rhs.base64Line();
     }
+
+    /** @brief Show the certificate in a native ui dialog.
+     *
+     * The dialog is external and handled by the OS on windows
+     * on GNU/Linux gcr-viewer is used.
+     *
+     * If parentWindow is not NULL it is used as a handle to the
+     * parent Window. Unused on GNU/Linux
+     *
+     * @returns true on success. false if no native dialog could be shown.
+     */
+     bool showNativeUI(void *parentWindow);
+
 private:
     /** @brief Helper function to parse the details of a certificate **/
     void parseDetails(const QByteArray& cert);
--- a/ui/certificateitemwidget.cpp	Mon Sep 29 13:02:41 2014 +0200
+++ b/ui/certificateitemwidget.cpp	Mon Sep 29 13:12:58 2014 +0200
@@ -63,16 +63,25 @@
             QLocale::system().toString(mCertificate.validFrom().date(), QLocale::ShortFormat)).arg(
             QLocale::system().toString(mCertificate.validTo().date(), QLocale::ShortFormat));
     const QString fpstring = tr("Fingerprint (SHA1): <code>%1</code>").arg(mCertificate.fingerprint());
+#ifdef Q_OS_WIN
+    mLabel->setText(QString::fromLatin1("<big><b><a href=showUi>%1</a></b></big><br/>%2<br/>%3<br/>%4").arg
+        (mCertificate.subjectCN()).arg(mCertificate.subjectO()).arg(validity).arg
+        (fpstring));
+#else
     mLabel->setText(QString::fromLatin1("<big><b>%1</b></big><br/>%2<br/>%3<br/>%4").arg
         (mCertificate.subjectCN()).arg(mCertificate.subjectO()).arg(validity).arg
         (fpstring));
+#endif
     mLabel->setTextFormat(Qt::RichText);
 
     mLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
 
     mLabel->setTextInteractionFlags(
+        Qt::LinksAccessibleByMouse |
+        Qt::LinksAccessibleByKeyboard |
         Qt::TextSelectableByMouse |
         Qt::TextSelectableByKeyboard);
+    connect(mLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(showCertDlg()));
     mButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
     connect(mButton, SIGNAL(toggled (bool)),
         this, SLOT(currentStateChanged(bool)));
@@ -85,6 +94,14 @@
     this->setLayout(layout);
 }
 
+void CertificateItemWidget::showCertDlg()
+{
+    /* This is a totally evil cast but legitimate on Windows
+     * HANDLES are only 32 bit even on Windows 64 bit */
+    qDebug() << "Showing native ui: " <<  mCertificate.showNativeUI((void*)effectiveWinId());
+    return;
+}
+
 bool CertificateItemWidget::state()
 {
     if (!mButton->isEnabled()) {
--- a/ui/certificateitemwidget.h	Mon Sep 29 13:02:41 2014 +0200
+++ b/ui/certificateitemwidget.h	Mon Sep 29 13:12:58 2014 +0200
@@ -66,8 +66,12 @@
     QToolButton *mButton;
 
 private slots:
+    /** @brief called when the certificate state has been changed */
     void currentStateChanged(bool state);
 
+    /** @brief Used to open the native cert dialog of the certificate */
+    void showCertDlg();
+
 signals:
     void stateChanged(bool state, const Certificate &cert);
 };

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