diff options
Diffstat (limited to 'Swift/QtUI/CAPICertificateSelector.cpp')
| -rw-r--r-- | Swift/QtUI/CAPICertificateSelector.cpp | 138 | 
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 ""; +	} +} + + +}  | 
 Swift