summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/TLS/CAPICertificate.cpp')
-rw-r--r--Swiften/TLS/CAPICertificate.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/Swiften/TLS/CAPICertificate.cpp b/Swiften/TLS/CAPICertificate.cpp
new file mode 100644
index 0000000..9a3bbc8
--- /dev/null
+++ b/Swiften/TLS/CAPICertificate.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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/TLS/CAPICertificate.h>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+
+namespace Swift {
+CAPICertificate::CAPICertificate(const std::string& capiUri)
+ : valid_(false), uri_(capiUri), certStoreHandle_(0), certStore_(), certName_() {
+ setUri(capiUri);
+}
+
+CAPICertificate::~CAPICertificate() {
+ if (certStoreHandle_) {
+ CertCloseStore(certStoreHandle_, 0);
+ }
+}
+
+bool CAPICertificate::isNull() const {
+ return uri_.empty() || !valid_;
+}
+
+const std::string& CAPICertificate::getCertStoreName() const {
+ return certStore_;
+}
+
+const std::string& CAPICertificate::getCertName() const {
+ return certName_;
+}
+
+void CAPICertificate::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_certStore_name;
+ size_t pos = capi_identity.find_first_of (':');
+
+ if (pos == std::string::npos) {
+ /* Using the default certificate store */
+ new_certStore_name = "MY";
+ certName_ = capi_identity;
+ }
+ else {
+ new_certStore_name = capi_identity.substr(0, pos);
+ certName_ = capi_identity.substr(pos + 1);
+ }
+
+ PCCERT_CONTEXT pCertContext = NULL;
+
+ if (certStoreHandle_ != NULL) {
+ if (new_certStore_name != certStore_) {
+ CertCloseStore(certStoreHandle_, 0);
+ certStoreHandle_ = NULL;
+ }
+ }
+
+ if (certStoreHandle_ == NULL) {
+ certStoreHandle_ = CertOpenSystemStore(0, certStore_.c_str());
+ if (!certStoreHandle_) {
+ return;
+ }
+ }
+
+ certStore_ = new_certStore_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(certStoreHandle_,
+ X509_ASN_ENCODING,
+ 0, // dwFindFlags
+ CERT_FIND_SUBJECT_STR_A,
+ certName_.c_str(), // *pvFindPara
+ NULL ); // pPrevCertContext
+
+ if (!pCertContext) {
+ 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;
+}
+
+}