summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/TLS')
-rw-r--r--Swiften/TLS/CAPICertificate.cpp26
-rw-r--r--Swiften/TLS/CertificateFactory.cpp4
-rw-r--r--Swiften/TLS/CertificateFactory.h2
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp12
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificate.h2
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp14
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h2
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.cpp367
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.h13
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp10
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContextFactory.h2
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp12
-rw-r--r--Swiften/TLS/SecureTransport/SecureTransportContext.mm70
-rw-r--r--Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp4
-rw-r--r--Swiften/TLS/ServerIdentityVerifier.cpp12
-rw-r--r--Swiften/TLS/ServerIdentityVerifier.h3
-rw-r--r--Swiften/TLS/TLSContext.cpp2
-rw-r--r--Swiften/TLS/TLSContext.h4
-rw-r--r--Swiften/TLS/TLSOptions.h54
-rw-r--r--Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp52
20 files changed, 535 insertions, 132 deletions
diff --git a/Swiften/TLS/CAPICertificate.cpp b/Swiften/TLS/CAPICertificate.cpp
index f10ad47..526b535 100644
--- a/Swiften/TLS/CAPICertificate.cpp
+++ b/Swiften/TLS/CAPICertificate.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2016 Isode Limited.
+ * Copyright (c) 2012-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -22,7 +22,7 @@
#define DEBUG_SCARD_STATUS(function, status) \
{ \
std::shared_ptr<boost::system::error_code> errorCode = std::make_shared<boost::system::error_code>(status, boost::system::system_category()); \
- SWIFT_LOG(debug) << std::hex << function << ": status: 0x" << status << ": " << errorCode->message() << std::endl; \
+ SWIFT_LOG(debug) << std::hex << function << ": status: 0x" << status << ": " << errorCode->message(); \
}
namespace Swift {
@@ -44,7 +44,7 @@ CAPICertificate::CAPICertificate(const std::string& capiUri, TimerFactory* timer
}
CAPICertificate::~CAPICertificate() {
- SWIFT_LOG(debug) << "Destroying the CAPICertificate" << std::endl;
+ SWIFT_LOG(debug) << "Destroying the CAPICertificate";
if (smartCardTimer_) {
smartCardTimer_->stop();
smartCardTimer_->onTick.disconnect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this));
@@ -53,7 +53,7 @@ CAPICertificate::~CAPICertificate() {
if (certStoreHandle_) {
if (CertCloseStore(certStoreHandle_, 0) == FALSE) {
- SWIFT_LOG(debug) << "Failed to close the certificate store handle" << std::endl;
+ SWIFT_LOG(debug) << "Failed to close the certificate store handle";
}
}
@@ -161,7 +161,7 @@ void CAPICertificate::setUri(const std::string& capiUri) {
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&len)) {
- SWIFT_LOG(error) << "Error while retrieving context properties" << std::endl;
+ SWIFT_LOG(error) << "Error while retrieving context properties";
return;
}
@@ -287,25 +287,25 @@ bool CAPICertificate::checkIfSmartCardPresent() {
switch (dwState) {
case SCARD_ABSENT:
- SWIFT_LOG(debug) << "Card absent." << std::endl;
+ SWIFT_LOG(debug) << "Card absent.";
break;
case SCARD_PRESENT:
- SWIFT_LOG(debug) << "Card present." << std::endl;
+ SWIFT_LOG(debug) << "Card present.";
break;
case SCARD_SWALLOWED:
- SWIFT_LOG(debug) << "Card swallowed." << std::endl;
+ SWIFT_LOG(debug) << "Card swallowed.";
break;
case SCARD_POWERED:
- SWIFT_LOG(debug) << "Card has power." << std::endl;
+ SWIFT_LOG(debug) << "Card has power.";
break;
case SCARD_NEGOTIABLE:
- SWIFT_LOG(debug) << "Card reset and waiting PTS negotiation." << std::endl;
+ SWIFT_LOG(debug) << "Card reset and waiting PTS negotiation.";
break;
case SCARD_SPECIFIC:
- SWIFT_LOG(debug) << "Card has specific communication protocols set." << std::endl;
+ SWIFT_LOG(debug) << "Card has specific communication protocols set.";
break;
default:
- SWIFT_LOG(debug) << "Unknown or unexpected card state." << std::endl;
+ SWIFT_LOG(debug) << "Unknown or unexpected card state.";
break;
}
@@ -332,7 +332,7 @@ bool CAPICertificate::checkIfSmartCardPresent() {
void CAPICertificate::handleSmartCardTimerTick() {
bool poll = checkIfSmartCardPresent();
if (lastPollingResult_ && !poll) {
- SWIFT_LOG(debug) << "CAPI Certificate detected that the certificate card was removed" << std::endl;
+ SWIFT_LOG(debug) << "CAPI Certificate detected that the certificate card was removed";
onCertificateCardRemoved();
}
lastPollingResult_ = poll;
diff --git a/Swiften/TLS/CertificateFactory.cpp b/Swiften/TLS/CertificateFactory.cpp
index aaf27d9..d4db3f4 100644
--- a/Swiften/TLS/CertificateFactory.cpp
+++ b/Swiften/TLS/CertificateFactory.cpp
@@ -23,9 +23,9 @@ namespace Swift {
CertificateFactory::~CertificateFactory() {
}
-std::vector<std::unique_ptr<Certificate>> CertificateFactory::createCertificateChain(const ByteArray& /* data */) {
+std::vector<std::shared_ptr<Certificate>> CertificateFactory::createCertificateChain(const ByteArray& /* data */) {
assert(false);
- return std::vector<std::unique_ptr<Certificate>>();
+ return std::vector<std::shared_ptr<Certificate>>();
}
PrivateKey::ref CertificateFactory::createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password) {
diff --git a/Swiften/TLS/CertificateFactory.h b/Swiften/TLS/CertificateFactory.h
index 619031c..873c36b 100644
--- a/Swiften/TLS/CertificateFactory.h
+++ b/Swiften/TLS/CertificateFactory.h
@@ -19,7 +19,7 @@ namespace Swift {
virtual ~CertificateFactory();
virtual Certificate* createCertificateFromDER(const ByteArray& der) = 0;
- virtual std::vector<std::unique_ptr<Certificate>> createCertificateChain(const ByteArray& data);
+ virtual std::vector<std::shared_ptr<Certificate>> createCertificateChain(const ByteArray& data);
PrivateKey::ref createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password = boost::optional<SafeByteArray>());
};
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp
index 8d2d965..66b650d 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2016 Isode Limited.
+ * Copyright (c) 2010-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -32,11 +32,19 @@ OpenSSLCertificate::OpenSSLCertificate(const ByteArray& der) {
#endif
cert = std::shared_ptr<X509>(d2i_X509(nullptr, &p, der.size()), X509_free);
if (!cert) {
- SWIFT_LOG(warning) << "Error creating certificate from DER data" << std::endl;
+// SWIFT_LOG(warning) << "Error creating certificate from DER data";
}
parse();
}
+void OpenSSLCertificate::incrementReferenceCount() const {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ X509_up_ref(cert.get());
+#else
+ CRYPTO_add(&(cert.get()->references), 1, CRYPTO_LOCK_EVP_PKEY);
+#endif
+}
+
ByteArray OpenSSLCertificate::toDER() const {
ByteArray result;
if (!cert) {
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h
index 186caea..64da82a 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h
@@ -45,6 +45,8 @@ namespace Swift {
return cert;
}
+ void incrementReferenceCount() const;
+
private:
void parse();
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp
index 5eb626b..73058a5 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp
@@ -7,6 +7,7 @@
#include <Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h>
#include <openssl/pem.h>
+#include <openssl/err.h>
namespace Swift {
@@ -20,8 +21,8 @@ Certificate* OpenSSLCertificateFactory::createCertificateFromDER(const ByteArray
return new OpenSSLCertificate(der);
}
-std::vector<std::unique_ptr<Certificate>> OpenSSLCertificateFactory::createCertificateChain(const ByteArray& data) {
- std::vector<std::unique_ptr<Certificate>> certificateChain;
+std::vector<std::shared_ptr<Certificate>> OpenSSLCertificateFactory::createCertificateChain(const ByteArray& data) {
+ std::vector<std::shared_ptr<Certificate>> certificateChain;
if (data.size() > std::numeric_limits<int>::max()) {
return certificateChain;
@@ -35,15 +36,20 @@ std::vector<std::unique_ptr<Certificate>> OpenSSLCertificateFactory::createCerti
auto x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr);
if (x509certFromPEM && openSSLCert) {
std::shared_ptr<X509> x509Cert(openSSLCert, X509_free);
- certificateChain.emplace_back(std::make_unique<OpenSSLCertificate>(x509Cert));
+ certificateChain.emplace_back(std::make_shared<OpenSSLCertificate>(x509Cert));
openSSLCert = nullptr;
while ((x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr)) != nullptr) {
std::shared_ptr<X509> x509Cert(openSSLCert, X509_free);
- certificateChain.emplace_back(std::make_unique<OpenSSLCertificate>(x509Cert));
+ certificateChain.emplace_back(std::make_shared<OpenSSLCertificate>(x509Cert));
openSSLCert = nullptr;
}
}
+ // Clear any (expected) errors which resulted from PEM parsing
+ // If we don't do this, any existing TLS context will detect these
+ // spurious errors and fail to work
+ ERR_clear_error();
+
return certificateChain;
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h
index 48e9b2c..a6974c8 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h
@@ -16,6 +16,6 @@ namespace Swift {
virtual ~OpenSSLCertificateFactory() override final;
virtual Certificate* createCertificateFromDER(const ByteArray& der) override final;
- virtual std::vector<std::unique_ptr<Certificate>> createCertificateChain(const ByteArray& data) override final;
+ virtual std::vector<std::shared_ptr<Certificate>> createCertificateChain(const ByteArray& data) override final;
};
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
index 5692e74..86b0504 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
@@ -42,6 +42,14 @@ namespace Swift {
static const int MAX_FINISHED_SIZE = 4096;
static const int SSL_READ_BUFFERSIZE = 8192;
+#define SSL_DEFAULT_VERIFY_DEPTH 5
+
+// Callback function declarations for certificate verification
+extern "C" {
+ static int certVerifyCallback(X509_STORE_CTX *store_ctx, void*);
+ static int verifyCallback(int preverify_ok, X509_STORE_CTX *ctx);
+}
+
static void freeX509Stack(STACK_OF(X509)* stack) {
sk_X509_free(stack);
}
@@ -90,7 +98,7 @@ namespace {
}
}
-OpenSSLContext::OpenSSLContext(Mode mode) : mode_(mode), state_(State::Start) {
+OpenSSLContext::OpenSSLContext(const TLSOptions& options, Mode mode) : mode_(mode), state_(State::Start) {
ensureLibraryInitialized();
context_ = createSSL_CTX(mode_);
SSL_CTX_set_options(context_.get(), SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
@@ -113,52 +121,58 @@ OpenSSLContext::OpenSSLContext(Mode mode) : mode_(mode), state_(State::Start) {
// TODO: implement OCSP support
// TODO: handle OCSP stapling see https://www.rfc-editor.org/rfc/rfc4366.txt
- // Load system certs
+
+ // Default for ignoreSystemTrustAnchors is false, i.e. load System TAs by default,
+ // to preserve previous behaviour
+ if (!options.ignoreSystemTrustAnchors) {
+ // Load system certs
#if defined(SWIFTEN_PLATFORM_WINDOWS)
- X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
- HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT");
- if (systemStore) {
- PCCERT_CONTEXT certContext = NULL;
- while (true) {
- certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext);
- if (!certContext) {
- break;
- }
- OpenSSLCertificate cert(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded));
- if (store && cert.getInternalX509()) {
- X509_STORE_add_cert(store, cert.getInternalX509().get());
+ X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
+ HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT");
+ if (systemStore) {
+ PCCERT_CONTEXT certContext = nullptr;
+ while (true) {
+ certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, nullptr, certContext);
+ if (!certContext) {
+ break;
+ }
+ OpenSSLCertificate cert(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded));
+ if (store && cert.getInternalX509()) {
+ X509_STORE_add_cert(store, cert.getInternalX509().get());
+ }
}
}
- }
#elif !defined(SWIFTEN_PLATFORM_MACOSX)
- SSL_CTX_set_default_verify_paths(context_.get());
+ SSL_CTX_set_default_verify_paths(context_.get());
#elif defined(SWIFTEN_PLATFORM_MACOSX) && !defined(SWIFTEN_PLATFORM_IPHONE)
- // On Mac OS X 10.5 (OpenSSL < 0.9.8), OpenSSL does not automatically look in the system store.
- // On Mac OS X 10.6 (OpenSSL >= 0.9.8), OpenSSL *does* look in the system store to determine trust.
- // However, if there is a certificate error, it will always emit the "Invalid CA" error if we didn't add
- // the certificates first. See
- // http://opensource.apple.com/source/OpenSSL098/OpenSSL098-27/src/crypto/x509/x509_vfy_apple.c
- // to understand why. We therefore add all certs from the system store ourselves.
- X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
- CFArrayRef anchorCertificates;
- if (SecTrustCopyAnchorCertificates(&anchorCertificates) == 0) {
- for (int i = 0; i < CFArrayGetCount(anchorCertificates); ++i) {
- SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(const_cast<void*>(CFArrayGetValueAtIndex(anchorCertificates, i)));
- CSSM_DATA certCSSMData;
- if (SecCertificateGetData(cert, &certCSSMData) != 0 || certCSSMData.Length == 0) {
- continue;
- }
- std::vector<unsigned char> certData;
- certData.resize(certCSSMData.Length);
- memcpy(&certData[0], certCSSMData.Data, certCSSMData.Length);
- OpenSSLCertificate certificate(certData);
- if (store && certificate.getInternalX509()) {
- X509_STORE_add_cert(store, certificate.getInternalX509().get());
+ // On Mac OS X 10.5 (OpenSSL < 0.9.8), OpenSSL does not automatically look in the system store.
+ // On Mac OS X 10.6 (OpenSSL >= 0.9.8), OpenSSL *does* look in the system store to determine trust.
+ // However, if there is a certificate error, it will always emit the "Invalid CA" error if we didn't add
+ // the certificates first. See
+ // http://opensource.apple.com/source/OpenSSL098/OpenSSL098-27/src/crypto/x509/x509_vfy_apple.c
+ // to understand why. We therefore add all certs from the system store ourselves.
+ X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
+ CFArrayRef anchorCertificates;
+ if (SecTrustCopyAnchorCertificates(&anchorCertificates) == 0) {
+ for (int i = 0; i < CFArrayGetCount(anchorCertificates); ++i) {
+ SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(const_cast<void*>(CFArrayGetValueAtIndex(anchorCertificates, i)));
+ CSSM_DATA certCSSMData;
+ if (SecCertificateGetData(cert, &certCSSMData) != 0 || certCSSMData.Length == 0) {
+ continue;
+ }
+ std::vector<unsigned char> certData;
+ certData.resize(certCSSMData.Length);
+ memcpy(&certData[0], certCSSMData.Data, certCSSMData.Length);
+ OpenSSLCertificate certificate(certData);
+ if (store && certificate.getInternalX509()) {
+ X509_STORE_add_cert(store, certificate.getInternalX509().get());
+ }
}
+ CFRelease(anchorCertificates);
}
- CFRelease(anchorCertificates);
- }
#endif
+ }
+ configure(options);
}
OpenSSLContext::~OpenSSLContext() {
@@ -175,6 +189,241 @@ void OpenSSLContext::initAndSetBIOs() {
SSL_set_bio(handle_.get(), readBIO_, writeBIO_);
}
+// This callback is called by OpenSSL when a client certificate needs to be verified.
+// In turn, this calls the verification callback which the user
+// of this OpenSSLContext has configured (if any).
+static int certVerifyCallback(X509_STORE_CTX* store_ctx, void* arg)
+{
+ OpenSSLContext* context = static_cast<OpenSSLContext *>(arg);
+
+ // Need to stash store_ctx pointer for use within verification
+ context->setX509StoreContext(store_ctx);
+
+ int ret;
+
+ // This callback shouldn't have been set up if the context doesn't
+ // have a verifyCertCallback set, but it doesn't hurt to double check
+ std::function<int (const TLSContext *)> cb = context->getVerifyCertCallback();
+ if (cb != nullptr) {
+ ret = cb(static_cast<const OpenSSLContext*>(context));
+ } else {
+ SWIFT_LOG(debug) << "certVerifyCallback called but context.verifyCertCallback is unset";
+ ret = 0;
+ }
+
+ context->setX509StoreContext(nullptr);
+ return ret;
+}
+
+// Convenience function to generate a text representation
+// of an X509 Name. This information is only used for logging.
+static std::string X509_NAME_to_text(X509_NAME* name)
+{
+ std::string nameString;
+
+ if (!name) {
+ return nameString;
+ }
+
+ std::unique_ptr<BIO, decltype(&BIO_free)> io(BIO_new(BIO_s_mem()), &BIO_free);
+ int r = X509_NAME_print_ex(io.get(), name, 0, XN_FLAG_RFC2253);
+ BIO_write(io.get(), "\0", 1);
+
+ if (r > 0) {
+ BUF_MEM* ptr = nullptr;
+ BIO_get_mem_ptr(io.get(), &ptr);
+ nameString = ptr->data;
+ }
+
+ return nameString;
+}
+
+// Check depth of certificate chain
+static int verifyCallback(int preverifyOk, X509_STORE_CTX* ctx)
+{
+ // Retrieve the pointer to the SSL of the connection currently treated
+ // and the application specific data stored into the SSL object.
+
+ int err = X509_STORE_CTX_get_error(ctx);
+ int depth = X509_STORE_CTX_get_error_depth(ctx);
+
+ SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+ SSL_CTX* sslctx = ssl ? SSL_get_SSL_CTX(ssl) : nullptr;
+ if (!sslctx) {
+ SWIFT_LOG(debug) << "verifyCallback: internal error";
+ return preverifyOk;
+ }
+
+ if (SSL_CTX_get_verify_mode(sslctx) == SSL_VERIFY_NONE) {
+ SWIFT_LOG(debug) << "verifyCallback: no verification required";
+ // No verification requested
+ return 1;
+ }
+
+ X509* errCert = X509_STORE_CTX_get_current_cert(ctx);
+ std::string subjectString;
+ if (errCert) {
+ X509_NAME* subjectName = X509_get_subject_name(errCert);
+ subjectString = X509_NAME_to_text(subjectName);
+ }
+
+ // Catch a too long certificate chain. The depth limit set using
+ // SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
+ // that whenever the "depth>verify_depth" condition is met, we
+ // have violated the limit and want to log this error condition.
+ // We must do it here, because the CHAIN_TOO_LONG error would not
+ // be found explicitly; only errors introduced by cutting off the
+ // additional certificates would be logged.
+ if (depth >= SSL_CTX_get_verify_depth(sslctx)) {
+ preverifyOk = 0;
+ err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
+ X509_STORE_CTX_set_error(ctx, err);
+ }
+
+ if (!preverifyOk) {
+ std::string issuerString;
+ if (errCert) {
+ X509_NAME* issuerName = X509_get_issuer_name(errCert);
+ issuerString = X509_NAME_to_text(issuerName);
+ }
+ SWIFT_LOG(debug) << "verifyCallback: verification error " <<
+ X509_verify_cert_error_string(err) << " depth: " <<
+ depth << " issuer: " << ((issuerString.length() > 0) ? issuerString : "<unknown>");
+ } else {
+ SWIFT_LOG(debug) << "verifyCallback: SSL depth: " << depth << " Subject: " <<
+ ((subjectString.length() > 0) ? subjectString : "<>");
+ }
+ // Always return "OK", as check on verification status
+ // will be performed once TLS handshake has completed,
+ // by calling OpenSSLContext::getVerificationErrorTypeForResult() to
+ // get the value set via X509_STORE_CTX_set_error() above.
+ return 1;
+}
+
+bool OpenSSLContext::configure(const TLSOptions &options)
+{
+ if (options.cipherSuites) {
+ std::string cipherSuites = *(options.cipherSuites);
+ if (SSL_CTX_set_cipher_list(context_.get(), cipherSuites.c_str()) != 1 ) {
+ SWIFT_LOG(debug) << "Failed to set cipher-suites";
+ return false;
+ }
+ }
+
+ if (options.context) {
+ const auto& contextId = *options.context;
+
+ if (SSL_CTX_set_session_id_context(context_.get(),
+ reinterpret_cast<const unsigned char *>(contextId.c_str()),
+ contextId.length()) != 1) {
+ SWIFT_LOG(debug) << "Failed to set context-id";
+ return false;
+ }
+ }
+
+ if (options.sessionCacheTimeout) {
+ int scto = *options.sessionCacheTimeout;
+ if (scto <= 0) {
+ SWIFT_LOG(debug) << "Invalid value for session-cache-timeout";
+ return false;
+ }
+ (void)SSL_CTX_set_timeout(context_.get(), scto);
+ if (SSL_CTX_get_timeout(context_.get()) != scto) {
+ SWIFT_LOG(debug) << "Failed to set session-cache-timeout";
+ return false;
+ }
+ }
+
+ if (options.verifyCertificateCallback) {
+ verifyCertCallback = *options.verifyCertificateCallback;
+ } else {
+ verifyCertCallback = nullptr;
+ }
+
+ if (options.verifyMode) {
+ TLSOptions::VerifyMode verify_mode = *options.verifyMode;
+ int mode;
+ switch (verify_mode) {
+ case TLSOptions::VerifyMode::None:
+ mode = SSL_VERIFY_NONE;
+ break;
+ case TLSOptions::VerifyMode::Required:
+ mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE;
+ break;
+ case TLSOptions::VerifyMode::Optional:
+ mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
+ break;
+ }
+
+ // Set up default certificate chain verification depth - may be overridden below
+ SSL_CTX_set_verify_depth(context_.get(), SSL_DEFAULT_VERIFY_DEPTH + 1);
+
+ // Set callbacks up
+ SSL_CTX_set_verify(context_.get(), mode, verifyCallback);
+
+ // Only set up certificate verification callback if a user callback has
+ // been configured via the TLSOptions
+ if (verifyCertCallback != nullptr) {
+ SSL_CTX_set_cert_verify_callback(context_.get(), certVerifyCallback, this);
+ }
+ }
+
+ if (options.verifyDepth) {
+ int depth = *options.verifyDepth;
+ if (depth <= 0) {
+ SWIFT_LOG(debug) << "Invalid value for verify-depth";
+ return false;
+ }
+
+ // Increase depth limit by one, so that verifyCallback() will log it
+ SSL_CTX_set_verify_depth(context_.get(), depth + 1);
+ }
+
+ auto updateOptionIfPresent = [this](boost::optional<bool> option, int flag) {
+ if (option) {
+ if (*option) {
+ SSL_CTX_set_options(context_.get(), flag);
+ }
+ else {
+ SSL_CTX_clear_options(context_.get(), flag);
+ }
+ }
+ };
+ updateOptionIfPresent(options.workaroundMicrosoftSessID, SSL_OP_MICROSOFT_SESS_ID_BUG);
+ updateOptionIfPresent(options.workaroundNetscapeChallenge, SSL_OP_NETSCAPE_CHALLENGE_BUG);
+ updateOptionIfPresent(options.workaroundNetscapeReuseCipherChange, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
+ updateOptionIfPresent(options.workaroundSSLRef2ReuseCertType, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
+ updateOptionIfPresent(options.workaroundMicrosoftBigSSLv3Buffer, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
+ updateOptionIfPresent(options.workaroundSSLeay080ClientDH, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
+ updateOptionIfPresent(options.workaroundTLSD5, SSL_OP_TLS_D5_BUG);
+ updateOptionIfPresent(options.workaroundTLSBlockPadding, SSL_OP_TLS_BLOCK_PADDING_BUG);
+ updateOptionIfPresent(options.workaroundDontInsertEmptyFragments, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+ updateOptionIfPresent(options.workaroundAll, SSL_OP_ALL);
+ updateOptionIfPresent(options.suppressSSLv2, SSL_OP_NO_SSLv2);
+ updateOptionIfPresent(options.suppressSSLv3, SSL_OP_NO_SSLv3);
+ updateOptionIfPresent(options.suppressTLSv1, SSL_OP_NO_TLSv1);
+ updateOptionIfPresent(options.disableTLSRollBackBug, SSL_OP_TLS_ROLLBACK_BUG);
+ updateOptionIfPresent(options.singleDHUse, SSL_OP_SINGLE_DH_USE);
+
+ if (options.trustAnchors) {
+ // Add any additional Trust Anchors which are present in the TLSOptions
+ X509_STORE* store = SSL_CTX_get_cert_store(context_.get());
+
+ if (store) {
+ for (auto& certificate : *options.trustAnchors) {
+ auto openSSLCert = dynamic_cast<OpenSSLCertificate*>(certificate.get());
+ if (openSSLCert && openSSLCert->getInternalX509()) {
+ X509_STORE_add_cert(store, openSSLCert->getInternalX509().get());
+ // Don't need to increment reference count as X509_STORE_add_cert does thiS
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+
void OpenSSLContext::accept() {
assert(mode_ == Mode::Server);
handle_ = std::unique_ptr<SSL>(SSL_new(context_.get()));
@@ -342,9 +591,9 @@ void OpenSSLContext::sendPendingDataToApplication() {
}
}
-bool OpenSSLContext::setCertificateChain(std::vector<std::unique_ptr<Certificate>>&& certificateChain) {
+bool OpenSSLContext::setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& certificateChain) {
if (certificateChain.size() == 0) {
- SWIFT_LOG(warning) << "Trying to load empty certificate chain." << std::endl;
+ SWIFT_LOG(debug) << "Trying to load empty certificate chain.";
return false;
}
@@ -354,6 +603,7 @@ bool OpenSSLContext::setCertificateChain(std::vector<std::unique_ptr<Certificate
return false;
}
+ // This increments the reference count on the X509 certificate automatically
if (SSL_CTX_use_certificate(context_.get(), openSSLCert->getInternalX509().get()) != 1) {
return false;
}
@@ -364,11 +614,13 @@ bool OpenSSLContext::setCertificateChain(std::vector<std::unique_ptr<Certificate
if (!openSSLCert) {
return false;
}
+
if (SSL_CTX_add_extra_chain_cert(context_.get(), openSSLCert->getInternalX509().get()) != 1) {
- SWIFT_LOG(warning) << "Trying to load empty certificate chain." << std::endl;
+ SWIFT_LOG(debug) << "Trying to load empty certificate chain.";
return false;
}
- certificate->release();
+ // Have to manually increment reference count as SSL_CTX_add_extra_chain_cert does not do so
+ openSSLCert->incrementReferenceCount();
}
}
@@ -414,16 +666,17 @@ bool OpenSSLContext::setPrivateKey(const PrivateKey::ref& privateKey) {
safePassword.push_back(0);
password = safePassword.data();
}
- auto resultKey = PEM_read_bio_PrivateKey(bio.get(), nullptr, empty_or_preset_password_cb, password);
+ // Make sure resultKey is tidied up by wrapping it in a shared_ptr
+ auto resultKey = std::shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio.get(), nullptr, empty_or_preset_password_cb, password), EVP_PKEY_free);
if (resultKey) {
if (handle_) {
- auto result = SSL_use_PrivateKey(handle_.get(), resultKey);;
+ auto result = SSL_use_PrivateKey(handle_.get(), resultKey.get());
if (result != 1) {
return false;
}
}
else {
- auto result = SSL_CTX_use_PrivateKey(context_.get(), resultKey);
+ auto result = SSL_CTX_use_PrivateKey(context_.get(), resultKey.get());
if (result != 1) {
return false;
}
@@ -486,7 +739,7 @@ bool OpenSSLContext::setDiffieHellmanParameters(const ByteArray& parametersInOpe
if (bio) {
BIO_write(bio.get(), vecptr(parametersInOpenSslDer), parametersInOpenSslDer.size());
auto result = 0L;
- if (auto dhparams = d2i_DHparams_bio(bio.get(), NULL)) {
+ if (auto dhparams = d2i_DHparams_bio(bio.get(), nullptr)) {
if (handle_) {
result = SSL_set_tmp_dh(handle_.get(), dhparams);
}
@@ -502,13 +755,33 @@ bool OpenSSLContext::setDiffieHellmanParameters(const ByteArray& parametersInOpe
std::vector<Certificate::ref> OpenSSLContext::getPeerCertificateChain() const {
std::vector<Certificate::ref> result;
+
+ // When this context is a server, the peer (client) certificate
+ // is obtained via SSL_get_peer_certificate, and any other
+ // certificates set by the peer are available via SSL_get_peer_cert_chain.
+ // When this context is a client, all of the server's certificates are
+ // obtained using SSL_get_peer_cert_chain
+ if (mode_ == Mode::Server) {
+ auto cert = SSL_get_peer_certificate(handle_.get());
+ if (cert) {
+ // Do not need to copy the returned cert as SSL_get_peer_certificate
+ // increments the reference count on the certificate
+ std::shared_ptr<X509> x509Cert(cert, X509_free);
+ Certificate::ref cert = std::make_shared<OpenSSLCertificate>(x509Cert);
+ result.push_back(cert);
+ }
+ }
+
STACK_OF(X509)* chain = SSL_get_peer_cert_chain(handle_.get());
for (int i = 0; i < sk_X509_num(chain); ++i) {
+ // Here we do need to copy the returned cert, since SSL_get_peer_cert_chain
+ // does not increment the reference count on each certificate
std::shared_ptr<X509> x509Cert(X509_dup(sk_X509_value(chain, i)), X509_free);
Certificate::ref cert = std::make_shared<OpenSSLCertificate>(x509Cert);
result.push_back(cert);
}
+
return result;
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h
index c18a6f4..8eb5758 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h
@@ -16,6 +16,7 @@
#include <Swiften/Base/ByteArray.h>
#include <Swiften/TLS/CertificateWithKey.h>
#include <Swiften/TLS/TLSContext.h>
+#include <Swiften/TLS/TLSOptions.h>
namespace std {
template<>
@@ -38,14 +39,14 @@ namespace std {
namespace Swift {
class OpenSSLContext : public TLSContext, boost::noncopyable {
public:
- OpenSSLContext(Mode mode);
+ OpenSSLContext(const TLSOptions& options, Mode mode);
virtual ~OpenSSLContext() override final;
void accept() override final;
void connect() override final;
void connect(const std::string& requestHostname) override final;
- bool setCertificateChain(std::vector<std::unique_ptr<Certificate>>&& certificateChain) override final;
+ bool setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& certificateChain) override final;
bool setPrivateKey(const PrivateKey::ref& privateKey) override final;
bool setClientCertificate(CertificateWithKey::ref cert) override final;
void setAbortTLSHandshake(bool abort) override final;
@@ -60,7 +61,11 @@ namespace Swift {
virtual ByteArray getFinishMessage() const override final;
virtual ByteArray getPeerFinishMessage() const override final;
+ void setX509StoreContext(X509_STORE_CTX *ptr) { x509_store_ctx = ptr; }
+ std::function<int (const TLSContext *)> getVerifyCertCallback() { return verifyCertCallback; }
+
private:
+ bool configure(const TLSOptions& options);
static void ensureLibraryInitialized();
static int handleServerNameCallback(SSL *ssl, int *ad, void *arg);
static CertificateVerificationError::Type getVerificationErrorTypeForResult(int);
@@ -81,5 +86,7 @@ namespace Swift {
BIO* readBIO_ = nullptr;
BIO* writeBIO_ = nullptr;
bool abortTLSHandshake_ = false;
- };
+ X509_STORE_CTX *x509_store_ctx = nullptr;
+ std::function<int (const TLSContext *)> verifyCertCallback = nullptr;
+ };
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
index a9ba5ab..e332ca8 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2018 Isode Limited.
+ * Copyright (c) 2010-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -21,8 +21,8 @@ bool OpenSSLContextFactory::canCreate() const {
return true;
}
-std::unique_ptr<TLSContext> OpenSSLContextFactory::createTLSContext(const TLSOptions&, TLSContext::Mode mode) {
- return std::unique_ptr<TLSContext>(new OpenSSLContext(mode));
+std::unique_ptr<TLSContext> OpenSSLContextFactory::createTLSContext(const TLSOptions& options, TLSContext::Mode mode) {
+ return std::make_unique<OpenSSLContext>(options, mode);
}
ByteArray OpenSSLContextFactory::convertDHParametersFromPEMToDER(const std::string& dhParametersInPEM) {
@@ -47,14 +47,14 @@ ByteArray OpenSSLContextFactory::convertDHParametersFromPEMToDER(const std::stri
void OpenSSLContextFactory::setCheckCertificateRevocation(bool check) {
if (check) {
- SWIFT_LOG(warning) << "CRL Checking not supported for OpenSSL" << std::endl;
+ SWIFT_LOG(warning) << "CRL Checking not supported for OpenSSL";
assert(false);
}
}
void OpenSSLContextFactory::setDisconnectOnCardRemoval(bool check) {
if (check) {
- SWIFT_LOG(warning) << "Smart cards not supported for OpenSSL" << std::endl;
+ SWIFT_LOG(warning) << "Smart cards not supported for OpenSSL";
}
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
index 95a2b0c..834e479 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2018 Isode Limited.
+ * Copyright (c) 2010-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp
index c07d009..722fb4a 100644
--- a/Swiften/TLS/Schannel/SchannelContext.cpp
+++ b/Swiften/TLS/Schannel/SchannelContext.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (c) 2012-2016 Isode Limited.
+ * Copyright (c) 2012-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -40,10 +40,10 @@ SchannelContext::SchannelContext(bool tls1_0Workaround) : state_(Start), secCont
//------------------------------------------------------------------------
SchannelContext::~SchannelContext() {
- SWIFT_LOG(debug) << "Destroying SchannelContext" << std::endl;
+ SWIFT_LOG(debug) << "Destroying SchannelContext";
if (myCertStore_) {
if (CertCloseStore(myCertStore_, 0) == FALSE) {
- SWIFT_LOG(debug) << "Failed to close the certificate store" << std::endl;
+ SWIFT_LOG(debug) << "Failed to close the certificate store";
}
}
}
@@ -52,7 +52,7 @@ SchannelContext::~SchannelContext() {
void SchannelContext::determineStreamSizes() {
if (QueryContextAttributes(contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_) != SEC_E_OK) {
- SWIFT_LOG(debug) << "QueryContextAttributes failed to determinate the stream size" << std::endl;
+ SWIFT_LOG(debug) << "QueryContextAttributes failed to determinate the stream size";
}
}
@@ -653,7 +653,7 @@ std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const {
SECURITY_STATUS status = QueryContextAttributes(contextHandle_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset());
if (status != SEC_E_OK) {
- SWIFT_LOG(debug) << "Error while Querying the Certificate Chain" << std::endl;
+ SWIFT_LOG(debug) << "Error while Querying the Certificate Chain";
return certificateChain;
}
certificateChain.push_back(std::make_shared<SchannelCertificate>(pServerCert));
@@ -688,7 +688,7 @@ ByteArray SchannelContext::getFinishMessage() const {
return createByteArray(((unsigned char*) bindings.Bindings) + bindings.Bindings->dwApplicationDataOffset + 11 /* tls-unique:*/, bindings.Bindings->cbApplicationDataLength - 11);
}
else {
- SWIFT_LOG(debug) << "Error while retrieving Finish Message" << std::endl;
+ SWIFT_LOG(debug) << "Error while retrieving Finish Message";
}
return ByteArray();
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContext.mm b/Swiften/TLS/SecureTransport/SecureTransportContext.mm
index 1ed636b..b4f7842 100644
--- a/Swiften/TLS/SecureTransport/SecureTransportContext.mm
+++ b/Swiften/TLS/SecureTransport/SecureTransportContext.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2016 Isode Limited.
+ * Copyright (c) 2015-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -72,14 +72,14 @@ CFArrayRef CreateClientCertificateChainAsCFArrayRef(CertificateWithKey::ref key)
break;
case errSecAuthFailed:
// Password did not work for decoding the certificate.
- SWIFT_LOG(warning) << "Invalid password." << std::endl;
+ SWIFT_LOG(warning) << "Invalid password.";
break;
case errSecDecode:
// Other decoding error.
- SWIFT_LOG(warning) << "PKCS12 decoding error." << std::endl;
+ SWIFT_LOG(warning) << "PKCS12 decoding error.";
break;
default:
- SWIFT_LOG(warning) << "Unknown error." << std::endl;
+ SWIFT_LOG(warning) << "Unknown error.";
}
if (securityError != errSecSuccess) {
@@ -110,20 +110,20 @@ SecureTransportContext::SecureTransportContext(bool checkCertificateRevocation)
// set IO callbacks
error = SSLSetIOFuncs(sslContext_.get(), &SecureTransportContext::SSLSocketReadCallback, &SecureTransportContext::SSLSocketWriteCallback);
if (error != noErr) {
- SWIFT_LOG(error) << "Unable to set IO functions to SSL context." << std::endl;
+ SWIFT_LOG(error) << "Unable to set IO functions to SSL context.";
sslContext_.reset();
}
error = SSLSetConnection(sslContext_.get(), this);
if (error != noErr) {
- SWIFT_LOG(error) << "Unable to set connection to SSL context." << std::endl;
+ SWIFT_LOG(error) << "Unable to set connection to SSL context.";
sslContext_.reset();
}
error = SSLSetSessionOption(sslContext_.get(), kSSLSessionOptionBreakOnServerAuth, true);
if (error != noErr) {
- SWIFT_LOG(error) << "Unable to set kSSLSessionOptionBreakOnServerAuth on session." << std::endl;
+ SWIFT_LOG(error) << "Unable to set kSSLSessionOptionBreakOnServerAuth on session.";
sslContext_.reset();
}
}
@@ -154,19 +154,19 @@ std::string SecureTransportContext::stateToString(State state) {
}
void SecureTransportContext::setState(State newState) {
- SWIFT_LOG(debug) << "Switch state from " << stateToString(state_) << " to " << stateToString(newState) << "." << std::endl;
+ SWIFT_LOG(debug) << "Switch state from " << stateToString(state_) << " to " << stateToString(newState) << ".";
state_ = newState;
}
void SecureTransportContext::connect() {
- SWIFT_LOG_ASSERT(state_ == None, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+ SWIFT_LOG_ASSERT(state_ == None, error) << "current state '" << stateToString(state_) << " invalid.";
if (clientCertificate_) {
CFArrayRef certs = CreateClientCertificateChainAsCFArrayRef(clientCertificate_);
if (certs) {
std::shared_ptr<CFArray> certRefs(certs, CFRelease);
OSStatus result = SSLSetCertificate(sslContext_.get(), certRefs.get());
if (result != noErr) {
- SWIFT_LOG(error) << "SSLSetCertificate failed with error " << result << "." << std::endl;
+ SWIFT_LOG(error) << "SSLSetCertificate failed with error " << result << ".";
}
}
}
@@ -174,23 +174,23 @@ void SecureTransportContext::connect() {
}
void SecureTransportContext::processHandshake() {
- SWIFT_LOG_ASSERT(state_ == None || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+ SWIFT_LOG_ASSERT(state_ == None || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid.";
OSStatus error = SSLHandshake(sslContext_.get());
if (error == errSSLWouldBlock) {
setState(Handshake);
}
else if (error == noErr) {
- SWIFT_LOG(debug) << "TLS handshake successful." << std::endl;
+ SWIFT_LOG(debug) << "TLS handshake successful.";
setState(HandshakeDone);
onConnected();
}
else if (error == errSSLPeerAuthCompleted) {
- SWIFT_LOG(debug) << "Received server certificate. Start verification." << std::endl;
+ SWIFT_LOG(debug) << "Received server certificate. Start verification.";
setState(Handshake);
verifyServerCertificate();
}
else {
- SWIFT_LOG(debug) << "Error returned from SSLHandshake call is " << error << "." << std::endl;
+ SWIFT_LOG(debug) << "Error returned from SSLHandshake call is " << error << ".";
fatalError(nativeToTLSError(error), std::make_shared<CertificateVerificationError>());
}
}
@@ -226,13 +226,13 @@ void SecureTransportContext::verifyServerCertificate() {
OSStatus cssmResult = 0;
switch(trustResult) {
case kSecTrustResultUnspecified:
- SWIFT_LOG(warning) << "Successful implicit validation. Result unspecified." << std::endl;
+ SWIFT_LOG(warning) << "Successful implicit validation. Result unspecified.";
break;
case kSecTrustResultProceed:
- SWIFT_LOG(warning) << "Validation resulted in explicitly trusted." << std::endl;
+ SWIFT_LOG(warning) << "Validation resulted in explicitly trusted.";
break;
case kSecTrustResultRecoverableTrustFailure:
- SWIFT_LOG(warning) << "recoverable trust failure" << std::endl;
+ SWIFT_LOG(warning) << "recoverable trust failure";
error = SecTrustGetCssmResultCode(trust, &cssmResult);
if (error == errSecSuccess) {
verificationError_ = CSSMErrorToVerificationError(cssmResult);
@@ -304,8 +304,8 @@ bool SecureTransportContext::setClientCertificate(CertificateWithKey::ref cert)
}
void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) {
- SWIFT_LOG(debug) << std::endl;
- SWIFT_LOG_ASSERT(state_ == HandshakeDone || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+ SWIFT_LOG(debug);
+ SWIFT_LOG_ASSERT(state_ == HandshakeDone || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid.";
append(readingBuffer_, data);
@@ -332,7 +332,7 @@ void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) {
break;
}
else {
- SWIFT_LOG(error) << "SSLRead failed with error " << error << ", read bytes: " << bytesRead << "." << std::endl;
+ SWIFT_LOG(error) << "SSLRead failed with error " << error << ", read bytes: " << bytesRead << ".";
fatalError(std::make_shared<TLSError>(), std::make_shared<CertificateVerificationError>());
return;
}
@@ -347,7 +347,7 @@ void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) {
}
break;
case Error:
- SWIFT_LOG(debug) << "Igoring received data in error state." << std::endl;
+ SWIFT_LOG(debug) << "Igoring received data in error state.";
break;
}
}
@@ -358,13 +358,13 @@ void SecureTransportContext::handleDataFromApplication(const SafeByteArray& data
OSStatus error = SSLWrite(sslContext_.get(), data.data(), data.size(), &processedBytes);
switch(error) {
case errSSLWouldBlock:
- SWIFT_LOG(warning) << "Unexpected because the write callback does not block." << std::endl;
+ SWIFT_LOG(warning) << "Unexpected because the write callback does not block.";
return;
case errSSLClosedGraceful:
case noErr:
return;
default:
- SWIFT_LOG(warning) << "SSLWrite returned error code: " << error << ", processed bytes: " << processedBytes << std::endl;
+ SWIFT_LOG(warning) << "SSLWrite returned error code: " << error << ", processed bytes: " << processedBytes;
fatalError(std::make_shared<TLSError>(), std::shared_ptr<CertificateVerificationError>());
}
}
@@ -376,7 +376,7 @@ std::vector<Certificate::ref> SecureTransportContext::getPeerCertificateChain()
typedef boost::remove_pointer<SecTrustRef>::type SecTrust;
std::shared_ptr<SecTrust> securityTrust;
- SecTrustRef secTrust = nullptr;;
+ SecTrustRef secTrust = nullptr;
OSStatus error = SSLCopyPeerTrust(sslContext_.get(), &secTrust);
if (error == noErr) {
securityTrust = std::shared_ptr<SecTrust>(secTrust, CFRelease);
@@ -390,7 +390,7 @@ std::vector<Certificate::ref> SecureTransportContext::getPeerCertificateChain()
}
}
else {
- SWIFT_LOG(warning) << "Failed to obtain peer trust structure; error = " << error << "." << std::endl;
+ SWIFT_LOG(warning) << "Failed to obtain peer trust structure; error = " << error << ".";
}
}
@@ -402,7 +402,7 @@ CertificateVerificationError::ref SecureTransportContext::getPeerCertificateVeri
}
ByteArray SecureTransportContext::getFinishMessage() const {
- SWIFT_LOG(warning) << "Access to TLS handshake finish message is not part of OS X Secure Transport APIs." << std::endl;
+ SWIFT_LOG(warning) << "Access to TLS handshake finish message is not part of OS X Secure Transport APIs.";
return ByteArray();
}
@@ -453,42 +453,42 @@ std::shared_ptr<CertificateVerificationError> SecureTransportContext::CSSMErrorT
std::shared_ptr<CertificateVerificationError> error;
switch(resultCode) {
case CSSMERR_TP_NOT_TRUSTED:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_NOT_TRUSTED" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_NOT_TRUSTED";
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Untrusted);
break;
case CSSMERR_TP_CERT_NOT_VALID_YET:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_NOT_VALID_YET" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_NOT_VALID_YET";
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::NotYetValid);
break;
case CSSMERR_TP_CERT_EXPIRED:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_EXPIRED" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_EXPIRED";
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Expired);
break;
case CSSMERR_TP_CERT_REVOKED:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_REVOKED" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_REVOKED";
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::Revoked);
break;
case CSSMERR_TP_VERIFY_ACTION_FAILED:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_VERIFY_ACTION_FAILED" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_VERIFY_ACTION_FAILED";
break;
case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK";
if (checkCertificateRevocation_) {
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed);
}
break;
case CSSMERR_APPLETP_OCSP_UNAVAILABLE:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_OCSP_UNAVAILABLE" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_OCSP_UNAVAILABLE";
if (checkCertificateRevocation_) {
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed);
}
break;
case CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE:
- SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE" << std::endl;
+ SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE";
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidPurpose);
break;
default:
- SWIFT_LOG(warning) << "unhandled CSSM error: " << resultCode << ", CSSM_TP_BASE_TP_ERROR: " << CSSM_TP_BASE_TP_ERROR << std::endl;
+ SWIFT_LOG(warning) << "unhandled CSSM error: " << resultCode << ", CSSM_TP_BASE_TP_ERROR: " << CSSM_TP_BASE_TP_ERROR;
error = std::make_shared<CertificateVerificationError>(CertificateVerificationError::UnknownError);
break;
}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp
index cc10987..ac399e1 100644
--- a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp
+++ b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2018 Isode Limited.
+ * Copyright (c) 2015-2019 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
@@ -39,7 +39,7 @@ void SecureTransportContextFactory::setCheckCertificateRevocation(bool b) {
void SecureTransportContextFactory::setDisconnectOnCardRemoval(bool b) {
disconnectOnCardRemoval_ = b;
if (disconnectOnCardRemoval_) {
- SWIFT_LOG(warning) << "Smart cards have not been tested yet" << std::endl;
+ SWIFT_LOG(warning) << "Smart cards have not been tested yet";
}
}
diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp
index 226e94b..18ea2aa 100644
--- a/Swiften/TLS/ServerIdentityVerifier.cpp
+++ b/Swiften/TLS/ServerIdentityVerifier.cpp
@@ -12,7 +12,7 @@
namespace Swift {
-ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter) : domainValid(false) {
+ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer) : domainValid(false), checkServer_(checkServer) {
domain = jid.getDomain();
boost::optional<std::string> domainResult = idnConverter->getIDNAEncoded(domain);
if (!!domainResult) {
@@ -36,12 +36,14 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) {
}
hasSAN |= !dnsNames.empty();
+ std::string prefix = (checkServer_) ? "_xmpp-server." : "_xmpp-client.";
+
// SRV names
std::vector<std::string> srvNames = certificate->getSRVNames();
for (const auto& srvName : srvNames) {
// Only match SRV names that begin with the service; this isn't required per
// spec, but we're being purist about this.
- if (boost::starts_with(srvName, "_xmpp-client.") && matchesDomain(srvName.substr(std::string("_xmpp-client.").size(), srvName.npos))) {
+ if (boost::starts_with(srvName, prefix) && matchesDomain(srvName.substr(prefix.size(), srvName.npos))) {
return true;
}
}
@@ -80,15 +82,15 @@ bool ServerIdentityVerifier::matchesDomain(const std::string& s) const {
if (dotIndex != matchDomain.npos) {
matchDomain = matchDomain.substr(dotIndex + 1, matchDomain.npos);
}
- return matchString == matchDomain;
+ return boost::iequals(matchString, matchDomain);
}
else {
- return s == encodedDomain;
+ return boost::iequals(s, encodedDomain);
}
}
bool ServerIdentityVerifier::matchesAddress(const std::string& s) const {
- return s == domain;
+ return boost::iequals(s, domain);
}
}
diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h
index f40c683..f2cf46f 100644
--- a/Swiften/TLS/ServerIdentityVerifier.h
+++ b/Swiften/TLS/ServerIdentityVerifier.h
@@ -18,7 +18,7 @@ namespace Swift {
class SWIFTEN_API ServerIdentityVerifier {
public:
- ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter);
+ ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer=false);
bool certificateVerifies(Certificate::ref);
@@ -30,5 +30,6 @@ namespace Swift {
std::string domain;
std::string encodedDomain;
bool domainValid;
+ bool checkServer_;
};
}
diff --git a/Swiften/TLS/TLSContext.cpp b/Swiften/TLS/TLSContext.cpp
index 666ea7f..fd31c2d 100644
--- a/Swiften/TLS/TLSContext.cpp
+++ b/Swiften/TLS/TLSContext.cpp
@@ -21,7 +21,7 @@ void TLSContext::connect(const std::string& /* serverName */) {
assert(false);
}
-bool TLSContext::setCertificateChain(std::vector<std::unique_ptr<Certificate>>&& /* certificateChain */) {
+bool TLSContext::setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& /* certificateChain */) {
assert(false);
return false;
}
diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h
index 003069f..f2dbdce 100644
--- a/Swiften/TLS/TLSContext.h
+++ b/Swiften/TLS/TLSContext.h
@@ -28,7 +28,7 @@ namespace Swift {
virtual void connect() = 0;
virtual void connect(const std::string& serverName);
- virtual bool setCertificateChain(std::vector<std::unique_ptr<Certificate>>&& /* certificateChain */);
+ virtual bool setCertificateChain(const std::vector<std::shared_ptr<Certificate>>& /* certificateChain */);
virtual bool setPrivateKey(const PrivateKey::ref& /* privateKey */);
virtual bool setClientCertificate(CertificateWithKey::ref cert) = 0;
@@ -50,7 +50,7 @@ namespace Swift {
virtual ByteArray getFinishMessage() const = 0;
virtual ByteArray getPeerFinishMessage() const;
- public:
+ public:
enum class Mode {
Client,
Server
diff --git a/Swiften/TLS/TLSOptions.h b/Swiften/TLS/TLSOptions.h
index dd7e920..e3faaf9 100644
--- a/Swiften/TLS/TLSOptions.h
+++ b/Swiften/TLS/TLSOptions.h
@@ -7,8 +7,11 @@
#pragma once
namespace Swift {
+ class TLSContext;
+ class Certificate;
- struct TLSOptions {
+ class TLSOptions {
+ public:
TLSOptions() : schannelTLS1_0Workaround(false) {
}
@@ -21,5 +24,54 @@ namespace Swift {
*/
bool schannelTLS1_0Workaround;
+ /**
+ * OpenSSL configuration flags
+ */
+ boost::optional<bool> workaroundMicrosoftSessID;
+ boost::optional<bool> workaroundNetscapeChallenge;
+ boost::optional<bool> workaroundNetscapeReuseCipherChange;
+ boost::optional<bool> workaroundSSLRef2ReuseCertType;
+ boost::optional<bool> workaroundMicrosoftBigSSLv3Buffer;
+ boost::optional<bool> workaroundSSLeay080ClientDH;
+ boost::optional<bool> workaroundTLSD5;
+ boost::optional<bool> workaroundTLSBlockPadding;
+ boost::optional<bool> workaroundDontInsertEmptyFragments;
+ boost::optional<bool> workaroundAll;
+ boost::optional<bool> suppressSSLv2;
+ boost::optional<bool> suppressSSLv3;
+ boost::optional<bool> suppressTLSv1;
+ boost::optional<bool> disableTLSRollBackBug;
+ boost::optional<bool> singleDHUse;
+
+ /**
+ * Other OpenSSL configuration items
+ */
+ boost::optional<std::string> cipherSuites;
+ boost::optional<std::string> context;
+ boost::optional<int> sessionCacheTimeout;
+ boost::optional<int> verifyDepth;
+
+ enum class VerifyMode {
+ None,
+ Required,
+ Optional
+ };
+ boost::optional<VerifyMode> verifyMode;
+
+ /**
+ * Callback for certificate verification
+ */
+
+ boost::optional<std::function<int(const TLSContext *)>> verifyCertificateCallback;
+
+ /**
+ * Allows specification of application-specific Trust Anchors
+ */
+ boost::optional<std::vector<std::shared_ptr<Certificate>>> trustAnchors;
+
+ /**
+ * Turns off automatic loading of system Trust Anchors
+ */
+ bool ignoreSystemTrustAnchors = false;
};
}
diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
index 30fe423..47f3db2 100644
--- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
+++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
@@ -35,6 +35,8 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testCertificateVerifies_WithMatchingInternationalXmppAddr);
CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithoutSAN);
CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithSAN);
+ CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithServerExpected);
+ CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected);
CPPUNIT_TEST_SUITE_END();
public:
@@ -58,6 +60,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
}
+ void testCertificateVerifies_WithMatchingDNSNameMixedCase() {
+ ServerIdentityVerifier testling(JID("foo@baR.com/baz"), idnConverter.get());
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addDNSName("Bar.com");
+
+ CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
+ }
+
void testCertificateVerifies_WithSecondMatchingDNSName() {
ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
SimpleCertificate::ref certificate(new SimpleCertificate());
@@ -131,6 +141,24 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
}
+ void testCertificateVerifies_WithMatchingSRVNameWithServerExpected() {
+ // Server-mode test which gets cert with "xmpp-server" SRV name
+ ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true);
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addSRVName("_xmpp-server.bar.com");
+
+ CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
+ }
+
+ void testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected() {
+ // Server-mode test which gets cert with "xmpp-client" SRV name
+ ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true);
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addSRVName("_xmpp-client.bar.com");
+
+ CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
+ }
+
void testCertificateVerifies_WithMatchingXmppAddr() {
ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
SimpleCertificate::ref certificate(new SimpleCertificate());
@@ -139,6 +167,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
}
+ void testCertificateVerifies_WithMatchingXmppAddrMixedCase() {
+ ServerIdentityVerifier testling(JID("foo@baR.com/baz"), idnConverter.get());
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addXMPPAddress("bAr.com");
+
+ CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
+ }
+
void testCertificateVerifies_WithMatchingXmppAddrWithWildcard() {
ServerIdentityVerifier testling(JID("foo@im.bar.com/baz"), idnConverter.get());
SimpleCertificate::ref certificate(new SimpleCertificate());
@@ -147,6 +183,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
}
+ void testCertificateVerifies_WithMatchingXmppAddrWithWildcardMixedCase() {
+ ServerIdentityVerifier testling(JID("foo@im.bAr.com/baz"), idnConverter.get());
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addXMPPAddress("*.baR.com");
+
+ CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
+ }
+
void testCertificateVerifies_WithMatchingInternationalXmppAddr() {
ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz"), idnConverter.get());
SimpleCertificate::ref certificate(new SimpleCertificate());
@@ -155,6 +199,14 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
}
+ void testCertificateVerifies_WithMatchingInternationalXmppAddrMixedCase() {
+ ServerIdentityVerifier testling(JID("foo@tRon\xc3\xa7.com/baz"), idnConverter.get());
+ SimpleCertificate::ref certificate(new SimpleCertificate());
+ certificate->addXMPPAddress("trOn\xc3\xa7.com");
+
+ CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
+ }
+
void testCertificateVerifies_WithMatchingCNWithoutSAN() {
ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
SimpleCertificate::ref certificate(new SimpleCertificate());