summaryrefslogtreecommitdiffstats
blob: 0d4768c8b5e116555c62d3dbe9a54997336d2c39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * Copyright (c) 2012 Isode Limited, London, England.
 * Licensed under the simplified BSD license.
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 */

#include <string>

#include "CAPICertificateSelector.h"

#define SECURITY_WIN32
#include <Windows.h>
#include <WinCrypt.h>
#include <cryptuiapi.h>

#include <Swiften/StringCodecs/Hexify.h>
#include <boost/algorithm/string.hpp>

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

// Size of the SHA1 hash
#define SHA1_HASH_LEN                20

static std::string getCertUri(PCCERT_CONTEXT cert, const char * cert_store_name) {
	DWORD cbHash = SHA1_HASH_LEN;
	BYTE aHash[SHA1_HASH_LEN];
	std::string ret("certstore:");

	ret += cert_store_name;
	ret += ":sha1:";

	if (CertGetCertificateContextProperty(cert,
		 CERT_HASH_PROP_ID,
		 aHash,
		 &cbHash) == FALSE ) {
		return "";
	}

	ByteArray byteArray = createByteArray((char *)(&aHash[0]), cbHash);
	ret += Hexify::hexify(byteArray);

	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 "";
	}
}

bool isCAPIURI(std::string uri) {
	return (boost::iequals(uri.substr(0, 10), "certstore:"));
}

}