summaryrefslogtreecommitdiffstats
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 /Swiften/TLS/CAPICertificate.h
parent64fc103d0d5d1d523d00dcc5b231715160475f7e (diff)
downloadswift-110eb87e848b85dd74a6f19413c775520a75ea35.zip
swift-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 'Swiften/TLS/CAPICertificate.h')
-rw-r--r--Swiften/TLS/CAPICertificate.h196
1 files changed, 196 insertions, 0 deletions
diff --git a/Swiften/TLS/CAPICertificate.h b/Swiften/TLS/CAPICertificate.h
new file mode 100644
index 0000000..fcdb4c2
--- /dev/null
+++ b/Swiften/TLS/CAPICertificate.h
@@ -0,0 +1,196 @@
+/*
+ * 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 <Swiften/Base/SafeByteArray.h>
+#include <Swiften/TLS/CertificateWithKey.h>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#define SECURITY_WIN32
+#include <WinCrypt.h>
+
+namespace Swift {
+ class CAPICertificate : public Swift::CertificateWithKey {
+ public:
+ CAPICertificate(const std::string& capiUri)
+ : valid_(false), uri_(capiUri), cert_store_handle_(0), cert_store_(NULL), cert_name_(NULL) {
+ setUri(capiUri);
+ }
+
+ virtual ~CAPICertificate() {
+ if (cert_store_handle_ != NULL)
+ {
+ CertCloseStore(cert_store_handle_, 0);
+ }
+ }
+
+ virtual bool isNull() const {
+ return uri_.empty() || !valid_;
+ }
+
+ virtual bool isPrivateKeyExportable() const {
+ /* We can check with CAPI, but for now the answer is "no" */
+ return false;
+ }
+
+ virtual const std::string& getCertStoreName() const {
+ return cert_store_;
+ }
+
+ virtual const std::string& getCertName() const {
+ return cert_name_;
+ }
+
+ const ByteArray& getData() const {
+////Might need to throw an exception here, or really generate PKCS12 blob from CAPI data?
+ assert(0);
+ }
+
+ void setData(const ByteArray& data) {
+ assert(0);
+ }
+
+ const SafeByteArray& getPassword() const {
+/////Can't pass NULL to createSafeByteArray!
+/////Should this throw an exception instead?
+ return createSafeByteArray("");
+ }
+
+ protected:
+ void setUri (const std::string& capiUri) {
+
+ valid_ = false;
+
+ /* Syntax: "certstore:" [<cert_store> ":"] <cert_id> */
+
+ if (!boost::iequals(capiUri.substr(0, 10), "certstore:")) {
+ return;
+ }
+
+ /* Substring of subject: uses "storename" */
+ std::string capi_identity = capiUri.substr(10);
+ std::string new_cert_store_name;
+ size_t pos = capi_identity.find_first_of (':');
+
+ if (pos == std::string::npos) {
+ /* Using the default certificate store */
+ new_cert_store_name = "MY";
+ cert_name_ = capi_identity;
+ } else {
+ new_cert_store_name = capi_identity.substr(0, pos);
+ cert_name_ = capi_identity.substr(pos + 1);
+ }
+
+ PCCERT_CONTEXT pCertContext = NULL;
+
+ if (cert_store_handle_ != NULL)
+ {
+ if (new_cert_store_name != cert_store_) {
+ CertCloseStore(cert_store_handle_, 0);
+ cert_store_handle_ = NULL;
+ }
+ }
+
+ if (cert_store_handle_ == NULL)
+ {
+ cert_store_handle_ = CertOpenSystemStore(0, cert_store_.c_str());
+ if (!cert_store_handle_)
+ {
+ return;
+ }
+ }
+
+ cert_store_ = new_cert_store_name;
+
+ /* NB: This might have to change, depending on how we locate certificates */
+
+ // Find client certificate. Note that this sample just searches for a
+ // certificate that contains the user name somewhere in the subject name.
+ pCertContext = CertFindCertificateInStore(cert_store_handle_,
+ X509_ASN_ENCODING,
+ 0, // dwFindFlags
+ CERT_FIND_SUBJECT_STR_A,
+ cert_name_.c_str(), // *pvFindPara
+ NULL ); // pPrevCertContext
+
+ if (pCertContext == NULL)
+ {
+ return;
+ }
+
+
+ /* Now verify that we can have access to the corresponding private key */
+
+ DWORD len;
+ CRYPT_KEY_PROV_INFO *pinfo;
+ HCRYPTPROV hprov;
+ HCRYPTKEY key;
+
+ if (!CertGetCertificateContextProperty(pCertContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ NULL,
+ &len))
+ {
+ CertFreeCertificateContext(pCertContext);
+ return;
+ }
+
+ pinfo = static_cast<CRYPT_KEY_PROV_INFO *>(malloc(len));
+ if (!pinfo) {
+ CertFreeCertificateContext(pCertContext);
+ return;
+ }
+
+ if (!CertGetCertificateContextProperty(pCertContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ pinfo,
+ &len))
+ {
+ CertFreeCertificateContext(pCertContext);
+ free(pinfo);
+ return;
+ }
+
+ CertFreeCertificateContext(pCertContext);
+
+ // Now verify if we have access to the private key
+ if (!CryptAcquireContextW(&hprov,
+ pinfo->pwszContainerName,
+ pinfo->pwszProvName,
+ pinfo->dwProvType,
+ 0))
+ {
+ free(pinfo);
+ return;
+ }
+
+ if (!CryptGetUserKey(hprov, pinfo->dwKeySpec, &key))
+ {
+ CryptReleaseContext(hprov, 0);
+ free(pinfo);
+ return;
+ }
+
+ CryptDestroyKey(key);
+ CryptReleaseContext(hprov, 0);
+ free(pinfo);
+
+ valid_ = true;
+ }
+
+ private:
+ bool valid_;
+ std::string uri_;
+
+ HCERTSTORE cert_store_handle_;
+
+ /* Parsed components of the uri_ */
+ std::string cert_store_;
+ std::string cert_name_;
+ };
+}