diff options
Diffstat (limited to 'Swiften/TLS/OpenSSL/OpenSSLContext.cpp')
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLContext.cpp | 141 |
1 files changed, 85 insertions, 56 deletions
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; } |