diff options
Diffstat (limited to 'Swiften/TLS')
-rw-r--r-- | Swiften/TLS/CAPICertificate.cpp | 151 | ||||
-rw-r--r-- | Swiften/TLS/CAPICertificate.h | 176 | ||||
-rw-r--r-- | Swiften/TLS/CertificateWithKey.h | 12 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLContext.cpp | 11 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLContext.h | 2 | ||||
-rw-r--r-- | Swiften/TLS/SConscript | 1 | ||||
-rw-r--r-- | Swiften/TLS/Schannel/SchannelContext.cpp | 27 | ||||
-rw-r--r-- | Swiften/TLS/Schannel/SchannelContext.h | 2 | ||||
-rw-r--r-- | Swiften/TLS/TLSContext.h | 4 |
9 files changed, 184 insertions, 202 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; +} + +} 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; |