summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
authorAlexey Melnikov <alexey.melnikov@isode.com>2012-02-13 17:54:23 (GMT)
committerKevin Smith <git@kismith.co.uk>2012-02-22 14:08:13 (GMT)
commit110eb87e848b85dd74a6f19413c775520a75ea35 (patch)
treeb10236387180fca676a29f24c747c9d0fd94d8dd /Swift
parent64fc103d0d5d1d523d00dcc5b231715160475f7e (diff)
downloadswift-contrib-110eb87e848b85dd74a6f19413c775520a75ea35.zip
swift-contrib-110eb87e848b85dd74a6f19413c775520a75ea35.tar.bz2
Initial implementation of using CAPI certificates with Schannel.
Introduced a new parent class for all certificates with keys (class CertificateWithKey is the new parent for PKCS12Certificate.) Switched to using "CertificateWithKey *" instead of "const CertificateWithKey&" Added calling of a Windows dialog for certificate selection when Schannel TLS implementation is used. This compiles, but is not tested. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
Diffstat (limited to 'Swift')
-rw-r--r--Swift/QtUI/CAPICertificateSelector.cpp138
-rw-r--r--Swift/QtUI/CAPICertificateSelector.h13
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp19
-rw-r--r--Swift/QtUI/SConscript3
4 files changed, 169 insertions, 4 deletions
diff --git a/Swift/QtUI/CAPICertificateSelector.cpp b/Swift/QtUI/CAPICertificateSelector.cpp
new file mode 100644
index 0000000..44f5793
--- /dev/null
+++ b/Swift/QtUI/CAPICertificateSelector.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012 Isode Limited, London, England.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <string>
+
+#define SECURITY_WIN32
+#include <Windows.h>
+#include <WinCrypt.h>
+#include <cryptuiapi.h>
+
+#include "CAPICertificateSelector.h"
+
+namespace Swift {
+
+#define cert_dlg_title L"TLS Client Certificate Selection"
+#define cert_dlg_prompt L"Select a certificate to use for authentication"
+/////Hmm, maybe we should not exlude the "location" column
+#define exclude_columns CRYPTUI_SELECT_LOCATION_COLUMN \
+ |CRYPTUI_SELECT_INTENDEDUSE_COLUMN
+
+
+
+static std::string getCertUri(PCCERT_CONTEXT cert, const char * cert_store_name) {
+ DWORD required_size;
+ char * comma;
+ char * p_in;
+ char * p_out;
+ char * subject_name;
+ std::string ret = std::string("certstore:") + cert_store_name + ":";
+
+ required_size = CertNameToStrA(cert->dwCertEncodingType,
+ &cert->pCertInfo->Subject,
+ /* Discard attribute names: */
+ CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
+ NULL,
+ 0);
+
+ subject_name = static_cast<char *>(malloc(required_size+1));
+
+ if (!CertNameToStrA(cert->dwCertEncodingType,
+ &cert->pCertInfo->Subject,
+ /* Discard attribute names: */
+ CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
+ subject_name,
+ required_size)) {
+ return "";
+ }
+
+ /* Now search for the "," (ignoring escapes)
+ and truncate the rest of the string */
+ if (subject_name[0] == '"') {
+ for (comma = subject_name + 1; comma[0]; comma++) {
+ if (comma[0] == '"') {
+ comma++;
+ if (comma[0] != '"') {
+ break;
+ }
+ }
+ }
+ } else {
+ comma = strchr(subject_name, ',');
+ }
+
+ if (comma != NULL) {
+ *comma = '\0';
+ }
+
+ /* We now need to unescape the returned RDN */
+ if (subject_name[0] == '"') {
+ for (p_in = subject_name + 1, p_out = subject_name; p_in[0]; p_in++, p_out++) {
+ if (p_in[0] == '"') {
+ p_in++;
+ }
+
+ p_out[0] = p_in[0];
+ }
+ p_out[0] = '\0';
+ }
+
+ ret += subject_name;
+ free(subject_name);
+
+ return ret;
+}
+
+std::string selectCAPICertificate() {
+
+ const char * cert_store_name = "MY";
+ PCCERT_CONTEXT cert;
+ DWORD store_flags;
+ HCERTSTORE hstore;
+ HWND hwnd;
+
+ store_flags = CERT_STORE_OPEN_EXISTING_FLAG |
+ CERT_STORE_READONLY_FLAG |
+ CERT_SYSTEM_STORE_CURRENT_USER;
+
+ hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, store_flags, cert_store_name);
+ if (!hstore) {
+ return "";
+ }
+
+
+////Does this handle need to be freed as well?
+ hwnd = GetForegroundWindow();
+ if (!hwnd) {
+ hwnd = GetActiveWindow();
+ }
+
+ /* Call Windows dialog to select a suitable certificate */
+ cert = CryptUIDlgSelectCertificateFromStore(hstore,
+ hwnd,
+ cert_dlg_title,
+ cert_dlg_prompt,
+ exclude_columns,
+ 0,
+ NULL);
+
+ if (hstore) {
+ CertCloseStore(hstore, 0);
+ }
+
+ if (cert) {
+ std::string ret = getCertUri(cert, cert_store_name);
+
+ CertFreeCertificateContext(cert);
+
+ return ret;
+ } else {
+ return "";
+ }
+}
+
+
+}
diff --git a/Swift/QtUI/CAPICertificateSelector.h b/Swift/QtUI/CAPICertificateSelector.h
new file mode 100644
index 0000000..9a0ee92
--- /dev/null
+++ b/Swift/QtUI/CAPICertificateSelector.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2012 Isode Limited, London, England.
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace Swift {
+ std::string selectCAPICertificate();
+}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index 1cd3206..6b9d389 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -41,6 +41,10 @@
#include <QtMainWindow.h>
#include <QtUtilities.h>
+#ifdef HAVE_SCHANNEL
+#include "CAPICertificateSelector.h"
+#endif
+
namespace Swift{
QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings) : QMainWindow(), settings_(settings) {
@@ -357,10 +361,17 @@ void QtLoginWindow::setLoginAutomatically(bool loginAutomatically) {
void QtLoginWindow::handleCertficateChecked(bool checked) {
if (checked) {
- certificateFile_ = QFileDialog::getOpenFileName(this, tr("Select an authentication certificate"), QString(), QString("*.cert;*.p12;*.pfx"));
- if (certificateFile_.isEmpty()) {
- certificateButton_->setChecked(false);
- }
+#ifdef HAVE_SCHANNEL
+ certificateFile_ = selectCAPICertificate();
+ if (certificateFile_.isEmpty()) {
+ certificateButton_->setChecked(false);
+ }
+#else
+ certificateFile_ = QFileDialog::getOpenFileName(this, tr("Select an authentication certificate"), QString(), QString("*.cert;*.p12;*.pfx"));
+ if (certificateFile_.isEmpty()) {
+ certificateButton_->setChecked(false);
+ }
+#endif
}
else {
certificateFile_ = "";
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index d37958f..a8b8c78 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -55,6 +55,8 @@ if env["PLATFORM"] == "win32" :
#myenv["LINKFLAGS"] = ["/SUBSYSTEM:CONSOLE"]
myenv.Append(LINKFLAGS = ["/SUBSYSTEM:WINDOWS"])
myenv.Append(LIBS = "qtmain")
+ if myenv.get("HAVE_SCHANNEL", 0) :
+ myenv.Append(LIBS = "Cryptui")
myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("#/Swift/resources/themes/Default"))))
@@ -151,6 +153,7 @@ if env["PLATFORM"] == "win32" :
# Adding it explicitly until i figure out why
myenv.Depends(res, "../Controllers/BuildVersion.h")
sources += [
+ "CAPICertificateSelector.cpp",
"WindowsNotifier.cpp",
"#/Swift/resources/Windows/Swift.res"
]