# HG changeset patch # User Andre Heinecke # Date 1411989178 -7200 # Node ID 265583011f24d7970eaf0cc39f951bd22bab4b84 # Parent d3d66d43365fd3d810a556998c761aeac9c6777a (issue123) Add possibility to open native certificate dialog This is currently only implemented for windows. diff -r d3d66d43365f -r 265583011f24 cinst/CMakeLists.txt --- 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) diff -r d3d66d43365f -r 265583011f24 cinst/windowsstore.c --- 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) diff -r d3d66d43365f -r 265583011f24 common/certhelp.c --- 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 diff -r d3d66d43365f -r 265583011f24 common/certhelp.h --- 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 +#include +#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 diff -r d3d66d43365f -r 265583011f24 ui/certificate.cpp --- 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 +#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 diff -r d3d66d43365f -r 265583011f24 ui/certificate.h --- 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); diff -r d3d66d43365f -r 265583011f24 ui/certificateitemwidget.cpp --- 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): %1").arg(mCertificate.fingerprint()); +#ifdef Q_OS_WIN + mLabel->setText(QString::fromLatin1("%1
%2
%3
%4").arg + (mCertificate.subjectCN()).arg(mCertificate.subjectO()).arg(validity).arg + (fpstring)); +#else mLabel->setText(QString::fromLatin1("%1
%2
%3
%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()) { diff -r d3d66d43365f -r 265583011f24 ui/certificateitemwidget.h --- 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); };