summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2012-02-22 13:31:39 (GMT)
committerKevin Smith <git@kismith.co.uk>2012-02-22 14:16:18 (GMT)
commitfa705718be1f98185557a09cf155ed66cbc740e2 (patch)
treeb73c65981c6e879df40c40c4b5436a4d4386e5a4
parent110eb87e848b85dd74a6f19413c775520a75ea35 (diff)
downloadswift-contrib-fa705718be1f98185557a09cf155ed66cbc740e2.zip
swift-contrib-fa705718be1f98185557a09cf155ed66cbc740e2.tar.bz2
Fix up for previous CAPI patch
Now connects successfully with or without TLS(with cert)
-rw-r--r--BuildTools/SCons/SConscript.boot1
-rw-r--r--COPYING14
-rw-r--r--Swift/Controllers/MainController.cpp15
-rw-r--r--Swift/Controllers/MainController.h4
-rw-r--r--Swift/Controllers/UIInterfaces/LoginWindow.h8
-rw-r--r--Swift/QtUI/CAPICertificateSelector.cpp7
-rw-r--r--Swift/QtUI/CAPICertificateSelector.h1
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp18
-rw-r--r--Swift/QtUI/SConscript3
-rw-r--r--Swiften/Client/CoreClient.cpp31
-rw-r--r--Swiften/Client/CoreClient.h12
-rw-r--r--Swiften/Session/SessionStream.cpp1
-rw-r--r--Swiften/Session/SessionStream.h10
-rw-r--r--Swiften/StreamStack/TLSLayer.cpp2
-rw-r--r--Swiften/StreamStack/TLSLayer.h4
-rw-r--r--Swiften/TLS/CAPICertificate.cpp151
-rw-r--r--Swiften/TLS/CAPICertificate.h176
-rw-r--r--Swiften/TLS/CertificateWithKey.h12
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.cpp11
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.h2
-rw-r--r--Swiften/TLS/SConscript1
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp27
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.h2
-rw-r--r--Swiften/TLS/TLSContext.h4
24 files changed, 260 insertions, 257 deletions
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index 2ea05db..188184c 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -134,6 +134,7 @@ if env["debug"] :
if env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/Zi", "/MDd"])
env.Append(LINKFLAGS = ["/DEBUG"])
+ env.Append(CPPDEFINES = ["_ITERATOR_DEBUG_LEVEL=0"])
else :
env.Append(CCFLAGS = ["-g"])
elif env["PLATFORM"] == "win32" :
diff --git a/COPYING b/COPYING
index 6bcfda6..15d92fa 100644
--- a/COPYING
+++ b/COPYING
@@ -839,3 +839,17 @@ Redistributions in binary form must reproduce the above copyright notice, this l
Neither the name of their organizations nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- END OF BSD LICENSE
+
+--- START OF SIMPLIFIED BSD LICENSE
+
+Copyright (c) 2012 Isode Limited, London, England.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WA RRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--- END OF SIMPLIFIED BSD LICENSE
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 4f869a7..d60bcbb 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -159,7 +159,7 @@ MainController::MainController(
}
- loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5));
+ loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5, _6));
loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&MainController::handlePurgeSavedLoginRequest, this, _1));
loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this));
loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this));
@@ -175,7 +175,8 @@ MainController::MainController(
if (loginAutomatically) {
profileSettings_ = new ProfileSettingsProvider(selectedLoginJID, settings_);
- handleLoginRequest(selectedLoginJID, cachedPassword, cachedCertificate, true, true);
+ /* FIXME: deal with autologin with a cert*/
+ handleLoginRequest(selectedLoginJID, cachedPassword, cachedCertificate, CertificateWithKey::ref(), true, true);
} else {
profileSettings_ = NULL;
}
@@ -416,7 +417,7 @@ void MainController::handleInputIdleChanged(bool idle) {
}
}
-void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificateFile, bool remember, bool loginAutomatically) {
+void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, bool remember, bool loginAutomatically) {
jid_ = JID(username);
if (!jid_.isValid() || jid_.getNode().empty()) {
loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'"));
@@ -427,7 +428,7 @@ void MainController::handleLoginRequest(const std::string &username, const std::
profileSettings_ = new ProfileSettingsProvider(username, settings_);
if (!settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) {
profileSettings_->storeString("jid", username);
- profileSettings_->storeString("certificate", certificateFile);
+ profileSettings_->storeString("certificate", certificatePath);
profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : "");
settings_->storeSetting(SettingConstants::LAST_LOGIN_JID, username);
settings_->storeSetting(SettingConstants::LOGIN_AUTOMATICALLY, loginAutomatically);
@@ -435,7 +436,7 @@ void MainController::handleLoginRequest(const std::string &username, const std::
}
password_ = password;
- certificateFile_ = certificateFile;
+ certificate_ = certificate;
performLoginFromCachedCredentials();
}
}
@@ -480,8 +481,8 @@ void MainController::performLoginFromCachedCredentials() {
presenceNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver());
eventNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1));
- if (!certificateFile_.empty()) {
- client_->setCertificate(certificateFile_);
+ if (certificate_ && !certificate_->isNull()) {
+ client_->setCertificate(certificate_);
}
boost::shared_ptr<Presence> presence(new Presence());
presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online)));
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 45e4ccf..14de4eb 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -91,7 +91,7 @@ namespace Swift {
private:
void resetClient();
void handleConnected();
- void handleLoginRequest(const std::string& username, const std::string& password, const std::string& certificateFile, bool remember, bool loginAutomatically);
+ void handleLoginRequest(const std::string& username, const std::string& password, const std::string& certificatePath, CertificateWithKey::ref certificate, bool remember, bool loginAutomatically);
void handleCancelLoginRequest();
void handleQuitRequest();
void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText);
@@ -153,7 +153,7 @@ namespace Swift {
XMPPURIController* xmppURIController_;
std::string vCardPhotoHash_;
std::string password_;
- std::string certificateFile_;
+ CertificateWithKey::ref certificate_;
boost::shared_ptr<ErrorEvent> lastDisconnectError_;
bool useDelayForLatency_;
UserSearchController* userSearchControllerChat_;
diff --git a/Swift/Controllers/UIInterfaces/LoginWindow.h b/Swift/Controllers/UIInterfaces/LoginWindow.h
index a8ee5a4..bbbbe35 100644
--- a/Swift/Controllers/UIInterfaces/LoginWindow.h
+++ b/Swift/Controllers/UIInterfaces/LoginWindow.h
@@ -1,16 +1,17 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2012 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
-#include "Swiften/Base/boost_bsignals.h"
+#include <Swiften/Base/boost_bsignals.h>
#include <boost/shared_ptr.hpp>
#include <string>
#include <Swiften/TLS/Certificate.h>
+#include <Swiften/TLS/CertificateWithKey.h>
namespace Swift {
class MainWindow;
@@ -25,7 +26,8 @@ namespace Swift {
virtual void setIsLoggingIn(bool loggingIn) = 0;
virtual void addAvailableAccount(const std::string& defaultJID, const std::string& defaultPassword, const std::string& defaultCertificate) = 0;
virtual void removeAvailableAccount(const std::string& jid) = 0;
- boost::signal<void (const std::string&, const std::string&, const std::string& /* certificateFile */, bool /* remember password*/, bool /* login automatically */)> onLoginRequest;
+ /** The certificate is what is used for login, the certificatePath is used for remembering paths to populate the loginwindow with*/
+ boost::signal<void (const std::string&, const std::string&, const std::string& /*CertificatePath*/, CertificateWithKey::ref /* clientCertificate */, bool /* remember password*/, bool /* login automatically */)> onLoginRequest;
virtual void setLoginAutomatically(bool loginAutomatically) = 0;
virtual void quit() = 0;
/** Blocking request whether a cert should be permanently trusted.*/
diff --git a/Swift/QtUI/CAPICertificateSelector.cpp b/Swift/QtUI/CAPICertificateSelector.cpp
index 44f5793..aa41d70 100644
--- a/Swift/QtUI/CAPICertificateSelector.cpp
+++ b/Swift/QtUI/CAPICertificateSelector.cpp
@@ -6,12 +6,14 @@
#include <string>
+#include "CAPICertificateSelector.h"
+
#define SECURITY_WIN32
#include <Windows.h>
#include <WinCrypt.h>
#include <cryptuiapi.h>
-#include "CAPICertificateSelector.h"
+#include <boost/algorithm/string.hpp>
namespace Swift {
@@ -134,5 +136,8 @@ std::string selectCAPICertificate() {
}
}
+bool isCAPIURI(std::string uri) {
+ return (boost::iequals(uri.substr(0, 10), "certstore:"));
+}
}
diff --git a/Swift/QtUI/CAPICertificateSelector.h b/Swift/QtUI/CAPICertificateSelector.h
index 9a0ee92..714f1c5 100644
--- a/Swift/QtUI/CAPICertificateSelector.h
+++ b/Swift/QtUI/CAPICertificateSelector.h
@@ -10,4 +10,5 @@
namespace Swift {
std::string selectCAPICertificate();
+ bool isCAPIURI(std::string uri);
}
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index 6b9d389..a3b7837 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -43,7 +43,9 @@
#ifdef HAVE_SCHANNEL
#include "CAPICertificateSelector.h"
+#include <Swiften/TLS/CAPICertificate.h>
#endif
+#include <Swiften/TLS/PKCS12Certificate.h>
namespace Swift{
@@ -345,7 +347,19 @@ void QtLoginWindow::loginClicked() {
return;
}
}
- onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), Q2PSTRING(certificateFile_), remember_->isChecked(), loginAutomatically_->isChecked());
+ CertificateWithKey::ref certificate;
+ std::string certificateString = Q2PSTRING(certificateFile_);
+#if defined(HAVE_SCHANNEL)
+ if (isCAPIURI(certificateString)) {
+ certificate = boost::make_shared<CAPICertificate>(certificateString);
+ } else {
+ certificate = boost::make_shared<PKCS12Certificate>(certificateString, createSafeByteArray(Q2PSTRING(password_->text())));
+ }
+#else
+ certificate = boost::make_shared<PKCS12Certificate>(certificateString, createSafeByteArray(Q2PSTRING(password_->text())));
+#endif
+
+ onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), certificateString, certificate, remember_->isChecked(), loginAutomatically_->isChecked());
if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { /* Mustn't remember logins */
username_->clearEditText();
password_->setText("");
@@ -362,7 +376,7 @@ void QtLoginWindow::setLoginAutomatically(bool loginAutomatically) {
void QtLoginWindow::handleCertficateChecked(bool checked) {
if (checked) {
#ifdef HAVE_SCHANNEL
- certificateFile_ = selectCAPICertificate();
+ certificateFile_ = P2QSTRING(selectCAPICertificate());
if (certificateFile_.isEmpty()) {
certificateButton_->setChecked(false);
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index a8b8c78..95c4305 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -57,6 +57,9 @@ if env["PLATFORM"] == "win32" :
myenv.Append(LIBS = "qtmain")
if myenv.get("HAVE_SCHANNEL", 0) :
myenv.Append(LIBS = "Cryptui")
+ myenv.Append(CPPDEFINES = "HAVE_SCHANNEL")
+ if env["debug"] :
+ myenv.Append(LINKFLAGS = ["/NODEFAULTLIB:msvcrt"])
myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("#/Swift/resources/themes/Default"))))
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 36bfe35..e2a8e5a 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -126,19 +126,6 @@ void CoreClient::bindSessionToStream() {
session_->start();
}
-bool CoreClient::isCAPIURI() {
-#ifdef HAVE_SCHANNEL
- if (!boost::iequals(certificate_.substr(0, 10), "certstore:")) {
- return false;
- }
-
- return true;
-
-#else
- return false;
-#endif
-}
-
/**
* Only called for TCP sessions. BOSH is handled inside the BOSHSessionStream.
*/
@@ -156,20 +143,8 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio
assert(!sessionStream_);
sessionStream_ = boost::make_shared<BasicSessionStream>(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getTLSContextFactory(), networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory());
- if (!certificate_.empty()) {
- CertificateWithKey* cert;
-
-#if defined(SWIFTEN_PLATFORM_WIN32)
- if (isCAPIURI()) {
- cert = new CAPICertificate(certificate_);
- } else {
- cert = new PKCS12Certificate(certificate_, password_);
- }
-#else
- cert = new PKCS12Certificate(certificate_, password_);
-#endif
-
- sessionStream_->setTLSCertificate(cert);
+ if (certificate_ && !certificate_->isNull()) {
+ sessionStream_->setTLSCertificate(certificate_);
}
sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1));
sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1));
@@ -190,7 +165,7 @@ void CoreClient::disconnect() {
}
}
-void CoreClient::setCertificate(const std::string& certificate) {
+void CoreClient::setCertificate(CertificateWithKey::ref certificate) {
certificate_ = certificate;
}
diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h
index 6712e03..1b875d2 100644
--- a/Swiften/Client/CoreClient.h
+++ b/Swiften/Client/CoreClient.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -15,6 +15,7 @@
#include <Swiften/Client/ClientError.h>
#include <Swiften/Client/ClientOptions.h>
#include <Swiften/Base/SafeByteArray.h>
+#include <Swiften/TLS/CertificateWithKey.h>
namespace Swift {
class ChainedConnector;
@@ -53,7 +54,12 @@ namespace Swift {
CoreClient(const JID& jid, const SafeByteArray& password, NetworkFactories* networkFactories);
~CoreClient();
- void setCertificate(const std::string& certificate);
+ /**
+ * Set a client certificate to use for strong authentication with the server.
+ * Ensure that it is of the correct type for the TLS engine in use.
+ * This means, largely, PKCS12Certificate for OpenSSL and CAPICertificate for CAPI.
+ */
+ void setCertificate(CertificateWithKey::ref certificate);
/**
* Connects the client to the server.
@@ -227,7 +233,7 @@ namespace Swift {
boost::shared_ptr<Connection> connection_;
boost::shared_ptr<SessionStream> sessionStream_;
boost::shared_ptr<ClientSession> session_;
- std::string certificate_;
+ CertificateWithKey::ref certificate_;
bool disconnectRequested_;
CertificateTrustChecker* certificateTrustChecker;
};
diff --git a/Swiften/Session/SessionStream.cpp b/Swiften/Session/SessionStream.cpp
index 487ad8b..0d73b63 100644
--- a/Swiften/Session/SessionStream.cpp
+++ b/Swiften/Session/SessionStream.cpp
@@ -9,7 +9,6 @@
namespace Swift {
SessionStream::~SessionStream() {
- delete certificate;
}
};
diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h
index 58015b3..2ff2a56 100644
--- a/Swiften/Session/SessionStream.h
+++ b/Swiften/Session/SessionStream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Remko Tronçon
+ * Copyright (c) 2010-2012 Remko Tronçon
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -36,7 +36,7 @@ namespace Swift {
Type type;
};
- SessionStream(): certificate(0) {}
+ SessionStream(): certificate() {}
virtual ~SessionStream();
@@ -58,7 +58,7 @@ namespace Swift {
virtual void resetXMPPParser() = 0;
- void setTLSCertificate(CertificateWithKey* cert) {
+ void setTLSCertificate(CertificateWithKey::ref cert) {
certificate = cert;
}
@@ -79,11 +79,11 @@ namespace Swift {
boost::signal<void (const SafeByteArray&)> onDataWritten;
protected:
- CertificateWithKey * getTLSCertificate() const {
+ CertificateWithKey::ref getTLSCertificate() const {
return certificate;
}
private:
- CertificateWithKey * certificate;
+ CertificateWithKey::ref certificate;
};
}
diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp
index b7efbcb..6d416bc 100644
--- a/Swiften/StreamStack/TLSLayer.cpp
+++ b/Swiften/StreamStack/TLSLayer.cpp
@@ -37,7 +37,7 @@ void TLSLayer::handleDataRead(const SafeByteArray& data) {
context->handleDataFromNetwork(data);
}
-bool TLSLayer::setClientCertificate(CertificateWithKey * certificate) {
+bool TLSLayer::setClientCertificate(CertificateWithKey::ref certificate) {
return context->setClientCertificate(certificate);
}
diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h
index 6dc9135..5aab26a 100644
--- a/Swiften/StreamStack/TLSLayer.h
+++ b/Swiften/StreamStack/TLSLayer.h
@@ -9,12 +9,12 @@
#include <Swiften/Base/SafeByteArray.h>
#include <Swiften/StreamStack/StreamLayer.h>
#include <Swiften/TLS/Certificate.h>
+#include <Swiften/TLS/CertificateWithKey.h>
#include <Swiften/TLS/CertificateVerificationError.h>
namespace Swift {
class TLSContext;
class TLSContextFactory;
- class CertificateWithKey;
class TLSLayer : public StreamLayer {
public:
@@ -22,7 +22,7 @@ namespace Swift {
~TLSLayer();
void connect();
- bool setClientCertificate(CertificateWithKey * cert);
+ bool setClientCertificate(CertificateWithKey::ref cert);
Certificate::ref getPeerCertificate() const;
boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
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;
+}
+
+}
diff --git a/Swiften/TLS/CAPICertificate.h b/Swiften/TLS/CAPICertificate.h
index fcdb4c2..d9e2704 100644
--- a/Swiften/TLS/CAPICertificate.h
+++ b/Swiften/TLS/CAPICertificate.h
@@ -9,188 +9,34 @@
#include <Swiften/Base/SafeByteArray.h>
#include <Swiften/TLS/CertificateWithKey.h>
-#include <boost/algorithm/string/predicate.hpp>
-
#define SECURITY_WIN32
+#include <Windows.h>
#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);
- }
+ CAPICertificate(const std::string& capiUri);
- PCCERT_CONTEXT pCertContext = NULL;
+ virtual ~CAPICertificate();
- if (cert_store_handle_ != NULL)
- {
- if (new_cert_store_name != cert_store_) {
- CertCloseStore(cert_store_handle_, 0);
- cert_store_handle_ = NULL;
- }
- }
+ virtual bool isNull() const;
- if (cert_store_handle_ == NULL)
- {
- cert_store_handle_ = CertOpenSystemStore(0, cert_store_.c_str());
- if (!cert_store_handle_)
- {
- return;
- }
- }
+ const std::string& getCertStoreName() const;
- cert_store_ = new_cert_store_name;
+ const std::string& getCertName() const;
- /* 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:
+ void setUri (const std::string& capiUri);
private:
bool valid_;
std::string uri_;
- HCERTSTORE cert_store_handle_;
+ HCERTSTORE certStoreHandle_;
/* Parsed components of the uri_ */
- std::string cert_store_;
- std::string cert_name_;
+ std::string certStore_;
+ std::string certName_;
};
}
diff --git a/Swiften/TLS/CertificateWithKey.h b/Swiften/TLS/CertificateWithKey.h
index 6f6ea39..1bdeb03 100644
--- a/Swiften/TLS/CertificateWithKey.h
+++ b/Swiften/TLS/CertificateWithKey.h
@@ -11,22 +11,12 @@
namespace Swift {
class CertificateWithKey {
public:
+ typedef boost::shared_ptr<CertificateWithKey> ref;
CertificateWithKey() {}
virtual ~CertificateWithKey() {}
virtual bool isNull() const = 0;
- virtual bool isPrivateKeyExportable() const = 0;
-
- virtual const std::string& getCertStoreName() const = 0;
-
- virtual const std::string& getCertName() const = 0;
-
- virtual const ByteArray& getData() const = 0;
-
- virtual void setData(const ByteArray& data) = 0;
-
- virtual const SafeByteArray& getPassword() const = 0;
};
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
index dd3462f..8076967 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
@@ -186,17 +186,14 @@ void OpenSSLContext::sendPendingDataToApplication() {
}
bool OpenSSLContext::setClientCertificate(CertificateWithKey * certificate) {
- if (!certificate || certificate->isNull()) {
- return false;
- }
-
- if (!certificate->isPrivateKeyExportable()) {
+ boost::shared_ptr<PKCS12Certificate> pkcs12Certificate = boost::dynamic_pointer_cast<PKCS12Certificate>(certificate);
+ if (!pkcs12Certificate || pkcs12Certificate->isNull()) {
return false;
}
// Create a PKCS12 structure
BIO* bio = BIO_new(BIO_s_mem());
- BIO_write(bio, vecptr(certificate->getData()), certificate->getData().size());
+ BIO_write(bio, vecptr(certificate->getData()), pkcs12Certificate->getData().size());
boost::shared_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free);
BIO_free(bio);
if (!pkcs12) {
@@ -207,7 +204,7 @@ bool OpenSSLContext::setClientCertificate(CertificateWithKey * certificate) {
X509 *certPtr = 0;
EVP_PKEY* privateKeyPtr = 0;
STACK_OF(X509)* caCertsPtr = 0;
- int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(certificate->getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr);
+ int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(pkcs12Certificate->getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr);
if (result != 1) {
return false;
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h
index b53e715..e98fb49 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h
@@ -22,7 +22,7 @@ namespace Swift {
~OpenSSLContext();
void connect();
- bool setClientCertificate(CertificateWithKey * cert);
+ bool setClientCertificate(CertificateWithKey::ref cert);
void handleDataFromNetwork(const SafeByteArray&);
void handleDataFromApplication(const SafeByteArray&);
diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript
index a71a446..0e95b8b 100644
--- a/Swiften/TLS/SConscript
+++ b/Swiften/TLS/SConscript
@@ -20,6 +20,7 @@ if myenv.get("HAVE_OPENSSL", 0) :
myenv.Append(CPPDEFINES = "HAVE_OPENSSL")
elif myenv.get("HAVE_SCHANNEL", 0) :
objects += myenv.StaticObject([
+ "CAPICertificate.cpp",
"Schannel/SchannelContext.cpp",
"Schannel/SchannelCertificate.cpp",
"Schannel/SchannelContextFactory.cpp",
diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp
index 6f50b3a..ddbebcb 100644
--- a/Swiften/TLS/Schannel/SchannelContext.cpp
+++ b/Swiften/TLS/Schannel/SchannelContext.cpp
@@ -4,8 +4,9 @@
* See Documentation/Licenses/BSD-simplified.txt for more information.
*/
-#include "Swiften/TLS/Schannel/SchannelContext.h"
-#include "Swiften/TLS/Schannel/SchannelCertificate.h"
+#include <Swiften/TLS/Schannel/SchannelContext.h>
+#include <Swiften/TLS/Schannel/SchannelCertificate.h>
+#include <Swiften/TLS/CAPICertificate.h>
namespace Swift {
@@ -17,7 +18,7 @@ SchannelContext::SchannelContext()
, m_verificationError(CertificateVerificationError::UnknownError)
, m_my_cert_store(NULL)
, m_cert_store_name("MY")
-, m_cert_name(NULL)
+, m_cert_name()
{
m_ctxtFlags = ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_CONFIDENTIALITY |
@@ -517,22 +518,18 @@ void SchannelContext::encryptAndSendData(const SafeByteArray& data)
//------------------------------------------------------------------------
-bool SchannelContext::setClientCertificate(CertificateWithKey * certificate)
+bool SchannelContext::setClientCertificate(CertificateWithKey::ref certificate)
{
- if (!certificate || certificate->isNull()) {
+ boost::shared_ptr<CAPICertificate> capiCertificate = boost::dynamic_pointer_cast<CAPICertificate>(certificate);
+ if (!capiCertificate || capiCertificate->isNull()) {
return false;
}
- if (!certificate->isPrivateKeyExportable()) {
- // We assume that the Certificate Store Name/Certificate Name
- // are valid at this point
- m_cert_store_name = certificate->getCertStoreName();
- m_cert_name = certificate->getCertName();
-
- return true;
- }
-
- return false;
+ // We assume that the Certificate Store Name/Certificate Name
+ // are valid at this point
+ m_cert_store_name = capiCertificate->getCertStoreName();
+ m_cert_name = capiCertificate->getCertName();
+ return true;
}
//------------------------------------------------------------------------
diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h
index 0cdb3d7..7726c41 100644
--- a/Swiften/TLS/Schannel/SchannelContext.h
+++ b/Swiften/TLS/Schannel/SchannelContext.h
@@ -37,7 +37,7 @@ namespace Swift
// TLSContext
//
virtual void connect();
- virtual bool setClientCertificate(CertificateWithKey * cert);
+ virtual bool setClientCertificate(CertificateWithKey::ref cert);
virtual void handleDataFromNetwork(const SafeByteArray& data);
virtual void handleDataFromApplication(const SafeByteArray& data);
diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h
index ada813a..9dee902 100644
--- a/Swiften/TLS/TLSContext.h
+++ b/Swiften/TLS/TLSContext.h
@@ -11,10 +11,10 @@
#include <Swiften/Base/SafeByteArray.h>
#include <Swiften/TLS/Certificate.h>
+#include <Swiften/TLS/CertificateWithKey.h>
#include <Swiften/TLS/CertificateVerificationError.h>
namespace Swift {
- class CertificateWithKey;
class TLSContext {
public:
@@ -22,7 +22,7 @@ namespace Swift {
virtual void connect() = 0;
- virtual bool setClientCertificate(CertificateWithKey * cert) = 0;
+ virtual bool setClientCertificate(CertificateWithKey::ref cert) = 0;
virtual void handleDataFromNetwork(const SafeByteArray&) = 0;
virtual void handleDataFromApplication(const SafeByteArray&) = 0;