summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI/CAPICertificateSelector.cpp')
-rw-r--r--Swift/QtUI/CAPICertificateSelector.cpp138
1 files changed, 138 insertions, 0 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 "";
+ }
+}
+
+
+}