diff options
Diffstat (limited to 'Swiften/TLS')
-rw-r--r-- | Swiften/TLS/CAPICertificate.cpp | 26 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp | 4 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp | 6 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLContext.cpp | 141 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp | 4 | ||||
-rw-r--r-- | Swiften/TLS/Schannel/SchannelContext.cpp | 12 | ||||
-rw-r--r-- | Swiften/TLS/SecureTransport/SecureTransportContext.mm | 70 | ||||
-rw-r--r-- | Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp | 4 | ||||
-rw-r--r-- | Swiften/TLS/ServerIdentityVerifier.cpp | 12 | ||||
-rw-r--r-- | Swiften/TLS/ServerIdentityVerifier.h | 3 | ||||
-rw-r--r-- | Swiften/TLS/TLSOptions.h | 5 | ||||
-rw-r--r-- | Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp | 52 |
12 files changed, 217 insertions, 122 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/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp index bb51428..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,7 +32,7 @@ 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(); } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp index fd94ec8..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 { @@ -44,6 +45,11 @@ std::vector<std::shared_ptr<Certificate>> OpenSSLCertificateFactory::createCerti } } + // 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/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp index 6dd75d6..86b0504 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp @@ -121,52 +121,57 @@ OpenSSLContext::OpenSSLContext(const TLSOptions& options, Mode mode) : mode_(mod // 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 = 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()); + 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); } @@ -202,7 +207,7 @@ static int certVerifyCallback(X509_STORE_CTX* store_ctx, void* arg) if (cb != nullptr) { ret = cb(static_cast<const OpenSSLContext*>(context)); } else { - SWIFT_LOG(warning) << "certVerifyCallback called but context.verifyCertCallback is unset" << std::endl; + SWIFT_LOG(debug) << "certVerifyCallback called but context.verifyCertCallback is unset"; ret = 0; } @@ -245,12 +250,12 @@ static int verifyCallback(int preverifyOk, X509_STORE_CTX* 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(error) << "verifyCallback: internal error" << std::endl; + SWIFT_LOG(debug) << "verifyCallback: internal error"; return preverifyOk; } if (SSL_CTX_get_verify_mode(sslctx) == SSL_VERIFY_NONE) { - SWIFT_LOG(info) << "verifyCallback: no verification required" << std::endl; + SWIFT_LOG(debug) << "verifyCallback: no verification required"; // No verification requested return 1; } @@ -281,14 +286,18 @@ static int verifyCallback(int preverifyOk, X509_STORE_CTX* ctx) X509_NAME* issuerName = X509_get_issuer_name(errCert); issuerString = X509_NAME_to_text(issuerName); } - SWIFT_LOG(error) << "verifyCallback: verification error" << - X509_verify_cert_error_string(err) << " depth: " << - depth << " issuer: " << ((issuerString.length() > 0) ? issuerString : "<unknown>") << std::endl; - } else { - SWIFT_LOG(info) << "verifyCallback: SSL depth: " << depth << " Subject: " << - ((subjectString.length() > 0) ? subjectString : "<>") << std::endl; - } - return preverifyOk; + 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) @@ -296,7 +305,7 @@ 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(error) << "Failed to set cipher-suites" << std::endl; + SWIFT_LOG(debug) << "Failed to set cipher-suites"; return false; } } @@ -307,7 +316,7 @@ bool OpenSSLContext::configure(const TLSOptions &options) if (SSL_CTX_set_session_id_context(context_.get(), reinterpret_cast<const unsigned char *>(contextId.c_str()), contextId.length()) != 1) { - SWIFT_LOG(error) << "Failed to set context-id" << std::endl; + SWIFT_LOG(debug) << "Failed to set context-id"; return false; } } @@ -315,12 +324,12 @@ bool OpenSSLContext::configure(const TLSOptions &options) if (options.sessionCacheTimeout) { int scto = *options.sessionCacheTimeout; if (scto <= 0) { - SWIFT_LOG(error) << "Invalid value for session-cache-timeout" << std::endl; + 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(error) << "Failed to set session-cache-timeout" << std::endl; + SWIFT_LOG(debug) << "Failed to set session-cache-timeout"; return false; } } @@ -362,7 +371,7 @@ bool OpenSSLContext::configure(const TLSOptions &options) if (options.verifyDepth) { int depth = *options.verifyDepth; if (depth <= 0) { - SWIFT_LOG(error) << "Invalid value for verify-depth" << std::endl; + SWIFT_LOG(debug) << "Invalid value for verify-depth"; return false; } @@ -584,7 +593,7 @@ void OpenSSLContext::sendPendingDataToApplication() { 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; } @@ -607,7 +616,7 @@ bool OpenSSLContext::setCertificateChain(const std::vector<std::shared_ptr<Certi } 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; } // Have to manually increment reference count as SSL_CTX_add_extra_chain_cert does not do so @@ -746,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/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp index 12445fd..e332ca8 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp @@ -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/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/TLSOptions.h b/Swiften/TLS/TLSOptions.h index 4109096..e3faaf9 100644 --- a/Swiften/TLS/TLSOptions.h +++ b/Swiften/TLS/TLSOptions.h @@ -68,5 +68,10 @@ namespace Swift { * 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()); |