From b856745048212175eac19536e40cf563b874f6b4 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 21 Aug 2020 20:14:26 +0300
Subject: [PATCH] SL-13835 SSL verification should not crash on invalid
 certificate

---
 indra/newview/llappcorehttp.cpp               | 22 +++++++++----------
 indra/newview/llsecapi.h                      | 10 +++++++++
 indra/newview/llsechandler_basic.cpp          |  6 +++--
 indra/newview/llstartup.cpp                   | 21 ++++++++++++++++--
 .../newview/skins/default/xui/en/strings.xml  |  1 +
 5 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp
index afa44149684..134a34137bd 100644
--- a/indra/newview/llappcorehttp.cpp
+++ b/indra/newview/llappcorehttp.cpp
@@ -522,20 +522,20 @@ void LLAppCoreHttp::refreshSettings(bool initial)
 LLCore::HttpStatus LLAppCoreHttp::sslVerify(const std::string &url, 
 	const LLCore::HttpHandler::ptr_t &handler, void *appdata)
 {
-	X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
-	LLCore::HttpStatus result;
-	LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
-	LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
-	LLSD validation_params = LLSD::emptyMap();
-	LLURI uri(url);
+    LLCore::HttpStatus result;
+    try
+    {
+        X509_STORE_CTX *ctx = static_cast<X509_STORE_CTX *>(appdata);
+        LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore("");
+        LLPointer<LLCertificateChain> chain = gSecAPIHandler->getCertificateChain(ctx);
+        LLSD validation_params = LLSD::emptyMap();
+        LLURI uri(url);
 
-	validation_params[CERT_HOSTNAME] = uri.hostName();
+        validation_params[CERT_HOSTNAME] = uri.hostName();
 
-	// *TODO: In the case of an exception while validating the cert, we need a way
-	// to pass the offending(?) cert back out. *Rider*
+        // *TODO: In the case of an exception while validating the cert, we need a way
+        // to pass the offending(?) cert back out. *Rider*
 
-	try
-	{
 		// don't validate hostname.  Let libcurl do it instead.  That way, it'll handle redirects
 		store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params);
 	}
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 69b6b329235..ae87cac53cd 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -345,6 +345,16 @@ class LLCertException: public LLException
 	LLSD mCertData;
 };
 
+class LLAllocationCertException : public LLCertException
+{
+public:
+    LLAllocationCertException(const LLSD& cert_data) : LLCertException(cert_data, "CertAllocationFailure")
+    {
+    }
+    virtual ~LLAllocationCertException() throw() {}
+protected:
+};
+
 class LLInvalidCertificate : public LLCertException
 {
 public:
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 8e524806442..8a922aee4f0 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -78,14 +78,16 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert,
 	BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length());
 	if(pem_bio == NULL)
 	{
-		LL_ERRS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+        LL_WARNS("SECAPI") << "Could not allocate an openssl memory BIO." << LL_ENDL;
+        LLTHROW(LLAllocationCertException(LLSD::emptyMap()));
 	}
 	mCert = NULL;
 	PEM_read_bio_X509(pem_bio, &mCert, 0, NULL);
 	BIO_free(pem_bio);
 	if (!mCert)
 	{
-		LL_ERRS("SECAPI") << "Could not decode certificate to x509." << LL_ENDL;
+        LL_WARNS("SECAPI") << "Could not decode certificate to x509." << LL_ENDL;
+        LLTHROW(LLInvalidCertificate(LLSD::emptyMap()));
 	}
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 1257add71d3..b130fd281cc 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1106,7 +1106,7 @@ bool idle_startup()
 				// If optional was skipped this case shouldn't 
 				// be reached.
 
-				LL_INFOS() << "Forcing a quit due to update." << LL_ENDL;
+				LL_INFOS("LLStartup") << "Forcing a quit due to update." << LL_ENDL;
 				LLLoginInstance::getInstance()->disconnect();
 				LLAppViewer::instance()->forceQuit();
 			}
@@ -1127,7 +1127,24 @@ bool idle_startup()
 					{
 						// This was a certificate error, so grab the certificate
 						// and throw up the appropriate dialog.
-						LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]);
+                        LLPointer<LLCertificate> certificate;
+                        try
+                        {
+                            certificate = gSecAPIHandler->getCertificate(response["certificate"]);
+                        }
+                        catch (LLCertException &cert_exception)
+                        {
+                            LL_WARNS("LLStartup", "SECAPI") << "Caught " << cert_exception.what() << " certificate expception on getCertificate()" << LL_ENDL;
+                            LLSD args;
+                            args["REASON"] = LLTrans::getString(cert_exception.what());
+
+                            LLNotificationsUtil::add("GeneralCertificateError", args, response,
+                                general_cert_done);
+
+                            reset_login();
+                            gSavedSettings.setBOOL("AutoLogin", FALSE);
+                            show_connect_box = true;
+                        }
 						if(certificate)
 						{
 							LLSD args = transform_cert_args(certificate);
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 73ee8332cc3..30416768cde 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -108,6 +108,7 @@ Voice Server Version: [VOICE_VERSION]
 	<string name="CertKeyUsage">The certificate returned by the server could not be used for SSL.  Please contact your Grid administrator.</string>
 	<string name="CertBasicConstraints">Too many certificates were in the servers Certificate chain.  Please contact your Grid administrator.</string>
 	<string name="CertInvalidSignature">The certificate signature returned by the Grid server could not be verified.  Please contact your Grid administrator.</string>
+	<string name="CertAllocationFailure">Failed to allocate openssl memory for certificate.</string>
 
 	<string name="LoginFailedNoNetwork">Network error: Could not establish connection, please check your network connection.</string>
 	<string name="LoginFailed">Login failed.</string>
-- 
GitLab