From 1a9d19d95527d717b89d4ebf45af81824fcbdf44 Mon Sep 17 00:00:00 2001
From: Roxanne Skelly <roxie@lindenlab.com>
Date: Fri, 3 Jul 2009 01:05:27 +0000
Subject: [PATCH] Initial secapi merge

svn merge -c112450  svn+ssh://svn.lindenlab.com/svn/linden/branches/giab-viewer/giab-viewer-1 giab-viewer-1-23

svn merge -c112913  svn+ssh://svn.lindenlab.com/svn/linden/branches/giab-viewer/giab-viewer-1 giab-viewer-1-23
---
 indra/newview/CMakeLists.txt         |  10 +
 indra/newview/llsecapi.cpp           |  69 ++++
 indra/newview/llsecapi.h             | 232 +++++++++++++
 indra/newview/llsechandler_basic.cpp | 490 +++++++++++++++++++++++++++
 indra/newview/llsechandler_basic.h   | 116 +++++++
 5 files changed, 917 insertions(+)
 create mode 100644 indra/newview/llsecapi.cpp
 create mode 100644 indra/newview/llsecapi.h
 create mode 100644 indra/newview/llsechandler_basic.cpp
 create mode 100644 indra/newview/llsechandler_basic.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 62cb8380c0..9430bb1d56 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -7,6 +7,7 @@ include(Boost)
 include(BuildVersion)
 include(DBusGlib)
 include(DirectX)
+include(OpenSSL)
 include(ELFIO)
 include(FMOD)
 include(OPENAL)
@@ -372,6 +373,8 @@ set(viewer_SOURCE_FILES
     llscrollingpanelparam.cpp
     llsearchcombobox.cpp
     llsearchhistory.cpp
+    llsecapi.cpp
+    llsechandler_basic.cpp
     llselectmgr.cpp
     llsidepanelappearance.cpp
     llsidepanelinventory.cpp
@@ -875,6 +878,8 @@ set(viewer_HEADER_FILES
     llscrollingpanelparam.h
     llsearchcombobox.h
     llsearchhistory.h
+    llsecapi.h
+    llsechandler_basic.h
     llselectmgr.h
     llsidepanelappearance.h
     llsidepanelinventory.h
@@ -1618,6 +1623,8 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${WINDOWS_LIBRARIES}
     ${XMLRPCEPI_LIBRARIES}
     ${ELFIO_LIBRARIES}
+    ${OPENSSL_LIBRARIES}
+    ${CRYPTO_LIBRARIES}
     ${LLLOGIN_LIBRARIES}
     ${GOOGLE_PERFTOOLS_LIBRARIES}
     )
@@ -1803,6 +1810,9 @@ if (LL_TESTS)
   #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
   #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
   #ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
+  #ADD_COMM_BUILD_TEST(llsecapi viewer "" llviewerprecompiledheaders.cpp llsechandler_basic.cpp)
+  #ADD_VIEWER_COMM_BUILD_TEST(llsechandler_basic viewer "")
+
 endif (LL_TESTS)
 
 
diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp
new file mode 100644
index 0000000000..c2cfde0dc7
--- /dev/null
+++ b/indra/newview/llsecapi.cpp
@@ -0,0 +1,69 @@
+/** 
+ * @file llsecapi.cpp
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llsecapi.h"
+#include "llsechandler_basic.h"
+#include <map>
+
+
+std::map<std::string, LLPointer<LLSecAPIHandler> > gHandlerMap;
+
+
+void initializeSecHandler()
+{
+	gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler();
+}
+// start using a given security api handler.  If the string is empty
+// the default is used
+LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
+{
+	if (gHandlerMap.find(handler_type) != gHandlerMap.end())
+	{
+		return gHandlerMap[handler_type];
+	}
+	else
+	{
+		return LLPointer<LLSecAPIHandler>(NULL);
+	}
+}
+// register a handler
+void registerSecHandler(const std::string& handler_type, 
+						LLPointer<LLSecAPIHandler>& handler)
+{
+	gHandlerMap[handler_type] = handler;
+}
+
+
+
+
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
new file mode 100644
index 0000000000..743d3d6770
--- /dev/null
+++ b/indra/newview/llsecapi.h
@@ -0,0 +1,232 @@
+/** 
+ * @file llsecapi.h
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSECAPI_H
+#define LLSECAPI_H
+#include <vector>
+#include <openssl/x509.h>
+
+// All error handling is via exceptions.
+
+
+#define CERT_SUBJECT_NAME "subject_name"
+#define CERT_ISSUER_NAME "issuer_name"
+		
+#define  CERT_SUBJECT_NAME_STRING "subject_name_string"
+#define CERT_ISSUER_NAME_STRING "issuer_name_string"
+		
+#define CERT_SERIAL_NUMBER "serial_number"
+		
+#define CERT_VALID_FROM "valid_from"
+#define CERT_VALID_TO "valid_to"
+#define CERT_SHA1_DIGEST "sha1_digest"
+#define CERT_MD5_DIGEST "md5_digest"
+
+#define BASIC_SECHANDLER "BASIC_SECHANDLER"
+
+
+// All error handling is via exceptions.
+
+class LLCertException
+{
+public:
+	LLCertException(const char* msg)
+	{
+		llerrs << "Certificate Error: " << msg << llendl;
+		mMsg = std::string(msg);
+	}
+protected:
+	std::string mMsg;
+};
+
+class LLProtectedDataException
+{
+public:
+	LLProtectedDataException(const char *msg) 
+	{
+		llerrs << "Certificate Error: " << msg << llendl;
+		mMsg = std::string(msg);
+	}
+protected:
+	std::string mMsg;
+};
+
+// class LLCertificate
+// parent class providing an interface for certifiate.
+// LLCertificates are considered unmodifiable
+// Certificates are pulled out of stores, or created via
+// factory calls
+class LLCertificate : public LLRefCount
+{
+	LOG_CLASS(LLCertificate);
+public:
+	LLCertificate() {}
+	
+	virtual ~LLCertificate() {}
+	
+	// return a PEM encoded certificate.  The encoding
+	// includes the -----BEGIN CERTIFICATE----- and end certificate elements
+	virtual std::string getPem()=0; 
+	
+	// return a DER encoded certificate
+	virtual std::vector<U8> getBinary()=0;  
+	
+	// return an LLSD object containing information about the certificate
+	// such as its name, signature, expiry time, serial number
+	virtual LLSD getLLSD()=0; 
+	
+	// return an openSSL X509 struct for the certificate
+	virtual X509* getOpenSSLX509()=0;
+
+};
+
+
+// class LLCertificateChain
+// Class representing a chain of certificates in order, with the 
+// 0th element being the CA
+class LLCertificateChain : public LLRefCount
+{
+	LOG_CLASS(LLCertificateChain);
+	static const int VT_SSL = 0;
+	static const int VT_AGENT_DOMAIN = 1;
+	static const int VT_GRID_DOMAIN = 1;
+	
+public:
+	LLCertificateChain() {}
+	
+	virtual ~LLCertificateChain() {}
+	
+	virtual X509_STORE getOpenSSLX509Store()=0;  // return an openssl X509_STORE  
+	// for this store
+	
+	virtual void appendCert(const LLCertificate& cert)=0;  // append a cert to the end 
+	//of the chain
+	
+	virtual LLPointer<LLCertificate>& operator [](int index)=0; // retrieve a certificate 
+	// from the chain by index
+	// -1 == end of chain
+	
+	virtual int len() const =0;  // return number of certificates in the chain
+	
+	// validate a certificate chain given the params.
+	// validation type indicates whether it's simply an SSL cert, or 
+	// something more specific
+	virtual bool validate(int validation_type, 
+						  const LLSD& validation_params) const =0;
+};
+
+
+// class LLCertificateStore
+// represents a store of certificates, typically a store of root CA
+// certificates.  The store can be persisted, and can be used to validate
+// a cert chain
+//
+class LLCertificateStore : public LLRefCount
+{
+public:
+	LLCertificateStore() {}
+	virtual ~LLCertificateStore() {}
+	
+	virtual X509_STORE getOpenSSLX509Store()=0;  // return an openssl X509_STORE  
+	// for this store
+	
+	// add a copy of a cert to the store
+	virtual void  append(const LLCertificate& cert)=0;
+	
+	// add a copy of a cert to the store
+	virtual void insert(const int index, const LLCertificate& cert)=0;
+	
+	// remove a certificate from the store
+	virtual void remove(int index)=0;
+	
+	// return a certificate at the index
+	virtual LLPointer<LLCertificate>& operator[](int index)=0;
+	// return the number of certs in the store
+	virtual int len() const =0;
+	
+	// load the store from a persisted location
+	virtual void load(const std::string& store_id)=0;
+	
+	// persist the store
+	virtual void save()=0;
+	
+	// return the store id
+	virtual std::string storeId()=0;
+	
+	// validate a cert chain
+	virtual bool validate(const LLCertificateChain& cert_chain) const=0;
+};
+
+
+// LLSecAPIHandler Class
+// Interface handler class for the various security storage handlers.
+class LLSecAPIHandler : public LLRefCount
+{
+public:
+	
+	LLSecAPIHandler() {}
+	virtual ~LLSecAPIHandler() {}
+	
+	// instantiate a certificate from a pem string
+	virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)=0;
+	
+	
+	// instiate a certificate from an openssl X509 structure
+	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0;
+	
+	// instantiate a chain from an X509_STORE_CTX
+	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0;
+	
+	// instantiate a cert store given it's id.  if a persisted version
+	// exists, it'll be loaded.  If not, one will be created (but not
+	// persisted)
+	virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)=0;
+	
+	// persist data in a protected store
+	virtual void setProtectedData(const std::string& data_type,
+								  const std::string& data_id,
+								  const LLSD& data)=0;
+	
+	// retrieve protected data
+	virtual LLSD getProtectedData(const std::string& data_type,
+								  const std::string& data_id)=0;
+};
+
+void secHandlerInitialize();
+				
+// retrieve a security api depending on the api type
+LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type);
+
+void registerSecHandler(const std::string& handler_type, 
+						LLPointer<LLSecAPIHandler>& handler);
+
+#endif // LL_SECAPI_H
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
new file mode 100644
index 0000000000..ab6bf034f1
--- /dev/null
+++ b/indra/newview/llsechandler_basic.cpp
@@ -0,0 +1,490 @@
+/** 
+ * @file llsechandler_basic.cpp
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2003&license=viewergpl$
+ * 
+ * Copyright (c) 2003-2000, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+#include "llsecapi.h"
+#include "llsechandler_basic.h"
+#include "llsdserialize.h"
+#include "llfile.h"
+#include "lldir.h"
+#include <vector>
+#include <ios>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/asn1.h>
+#include <openssl/rand.h>
+#include <iostream>
+#include <iomanip>
+#include <time.h>
+
+// 128 bits of salt data...
+#define STORE_SALT_SIZE 16 
+#define BUFFER_READ_SIZE 256
+
+
+LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) 
+{
+	
+	// BIO_new_mem_buf returns a read only bio, but takes a void* which isn't const
+	// so we need to cast it.
+	BIO * pem_bio = BIO_new_mem_buf((void*)pem_cert.c_str(), pem_cert.length());
+	
+	mCert = NULL;
+	PEM_read_bio_X509(pem_bio, &mCert, 0, NULL);
+	BIO_free(pem_bio);
+	if (!mCert)
+	{
+		throw LLCertException("Error parsing certificate");
+	}
+}
+
+
+LLBasicCertificate::LLBasicCertificate(X509* pCert) 
+{
+	if (!pCert || !pCert->cert_info)
+	{
+		throw LLCertException("Invalid certificate");
+	}	
+	mCert = X509_dup(pCert);
+}
+
+LLBasicCertificate::~LLBasicCertificate() 
+{
+
+	X509_free(mCert);
+}
+
+//
+// retrieve the pem using the openssl functionality
+std::string LLBasicCertificate::getPem()
+{ 
+	char * pem_bio_chars = NULL;
+	// a BIO is the equivalent of a 'std::stream', and
+	// can be a file, mem stream, whatever.  Grab a memory based
+	// BIO for the result
+	BIO *pem_bio = BIO_new(BIO_s_mem());
+	if (!pem_bio)
+	{
+		throw LLCertException("couldn't allocate memory buffer");		
+	}
+	PEM_write_bio_X509(pem_bio, mCert);
+	int length = BIO_get_mem_data(pem_bio, &pem_bio_chars);
+	std::string result = std::string(pem_bio_chars, length);
+	BIO_free(pem_bio);
+	return result;
+}
+
+// get the DER encoding for the cert
+// DER is a binary encoding format for certs...
+std::vector<U8> LLBasicCertificate::getBinary()
+{ 
+	U8 * der_bio_data = NULL;
+	// get a memory bio 
+	BIO *der_bio = BIO_new(BIO_s_mem());
+	if (!der_bio)
+	{
+		throw LLCertException("couldn't allocate memory buffer");		
+	}
+	i2d_X509_bio(der_bio, mCert);
+	int length = BIO_get_mem_data(der_bio, &der_bio_data);
+	std::vector<U8> result(length);
+	// vectors are guranteed to be a contiguous chunk of memory.
+	memcpy(&result[0], der_bio_data,  length);
+	BIO_free(der_bio);
+	return result;
+}
+
+
+LLSD LLBasicCertificate::getLLSD()
+{ 
+	LLSD result;
+
+	// call the various helpers to build the LLSD
+	result[CERT_SUBJECT_NAME] = cert_name_from_X509_NAME(X509_get_subject_name(mCert));
+	result[CERT_ISSUER_NAME] = cert_name_from_X509_NAME(X509_get_issuer_name(mCert));
+	result[CERT_SUBJECT_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_subject_name(mCert));
+	result[CERT_ISSUER_NAME_STRING] = cert_string_name_from_X509_NAME(X509_get_issuer_name(mCert));
+	ASN1_INTEGER *sn = X509_get_serialNumber(mCert);
+	if (sn != NULL)
+	{
+		result[CERT_SERIAL_NUMBER] = cert_string_from_asn1_integer(sn);
+	}
+	
+	result[CERT_VALID_TO] = cert_date_from_asn1_time(X509_get_notAfter(mCert));
+	result[CERT_VALID_FROM] = cert_date_from_asn1_time(X509_get_notBefore(mCert));
+	result[CERT_SHA1_DIGEST] = cert_get_digest("sha1", mCert);
+	result[CERT_MD5_DIGEST] = cert_get_digest("md5", mCert);
+
+
+
+	return result; 
+}
+
+X509* LLBasicCertificate::getOpenSSLX509()
+{ 
+	return X509_dup(mCert); 
+}  
+
+// generate a single string containing the subject or issuer
+// name of the cert.
+std::string cert_string_name_from_X509_NAME(X509_NAME* name)
+{
+	char * name_bio_chars = NULL;
+	// get a memory bio
+	BIO *name_bio = BIO_new(BIO_s_mem());
+	// stream the name into the bio.  The name will be in the 'short name' format
+	X509_NAME_print_ex(name_bio, name, 0, XN_FLAG_RFC2253);
+	int length = BIO_get_mem_data(name_bio, &name_bio_chars);
+	std::string result = std::string(name_bio_chars, length);
+	BIO_free(name_bio);
+	return result;
+}
+
+// generate an LLSD from a certificate name (issuer or subject name).  
+// the name will be strings indexed by the 'long form'
+LLSD cert_name_from_X509_NAME(X509_NAME* name)
+{
+	LLSD result = LLSD::emptyMap();
+	int name_entries = X509_NAME_entry_count(name);
+	for (int entry_index=0; entry_index < name_entries; entry_index++) 
+	{
+		char buffer[32];
+		X509_NAME_ENTRY *entry = X509_NAME_get_entry(name, entry_index);
+		
+		std::string name_value = std::string((const char*)M_ASN1_STRING_data(X509_NAME_ENTRY_get_data(entry)), 
+											 M_ASN1_STRING_length(X509_NAME_ENTRY_get_data(entry)));
+
+		ASN1_OBJECT* name_obj = X509_NAME_ENTRY_get_object(entry);		
+		OBJ_obj2txt(buffer, sizeof(buffer), name_obj, 0);
+		std::string obj_buffer_str = std::string(buffer);
+		result[obj_buffer_str] = name_value;
+	}
+	
+	return result;
+}
+
+// Generate a string from an ASN1 integer.  ASN1 Integers are
+// bignums, so they can be 'infinitely' long, therefore we
+// cannot simply use a conversion to U64 or something.
+// We retrieve as a readable string for UI
+
+std::string cert_string_from_asn1_integer(ASN1_INTEGER* value)
+{
+	BIGNUM *bn = ASN1_INTEGER_to_BN(value, NULL);
+	char * ascii_bn = BN_bn2hex(bn);
+
+	BN_free(bn);
+
+	std::string result(ascii_bn);
+	OPENSSL_free(ascii_bn);
+	return result;
+}
+
+// retrieve a date structure from an ASN1 time, for 
+// validity checking.
+LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time)
+{
+	
+	struct tm timestruct = {0};
+	int i = asn1_time->length;
+	
+	if (i < 10)
+		throw LLCertException("invalid certificate time value");
+	
+	// convert the date from the ASN1 time (which is a string in ZULU time), to
+	// a timeval.
+	timestruct.tm_year = (asn1_time->data[0]-'0') * 10 + (asn1_time->data[1]-'0');
+	
+	/* Deal with Year 2000 */
+	if (timestruct.tm_year < 70)
+		timestruct.tm_year += 100;
+	
+	timestruct.tm_mon = (asn1_time->data[2]-'0') * 10 + (asn1_time->data[3]-'0') - 1;
+	timestruct.tm_mday = (asn1_time->data[4]-'0') * 10 + (asn1_time->data[5]-'0');
+	timestruct.tm_hour = (asn1_time->data[6]-'0') * 10 + (asn1_time->data[7]-'0');
+	timestruct.tm_min = (asn1_time->data[8]-'0') * 10 + (asn1_time->data[9]-'0');
+	timestruct.tm_sec = (asn1_time->data[10]-'0') * 10 + (asn1_time->data[11]-'0');
+	
+	return LLDate((F64)mktime(&timestruct));
+}
+
+// Generate a string containing a digest.  The digest time is 'ssh1' or
+// 'md5', and the resulting string is of the form "aa:12:5c:' and so on
+std::string cert_get_digest(const std::string& digest_type, X509 *cert)
+{
+	unsigned char digest_data[1024];
+	unsigned int len = 1024;
+	std::stringstream result;
+	const EVP_MD* digest = NULL;
+	OpenSSL_add_all_digests();
+	// we could use EVP_get_digestbyname, but that requires initializer code which
+	// would require us to complicate things by plumbing it into the system.
+	if (digest_type == "md5")
+	{
+		digest = EVP_md5();
+	}
+	else if (digest_type == "sha1")
+	{
+		digest = EVP_sha1();
+	}
+	else
+	{
+		throw LLCertException("Invalid digest");
+	}
+
+	X509_digest(cert, digest, digest_data, &len);
+	result << std::hex << std::setprecision(2);
+	for (unsigned int i=0; i < len; i++)
+	{
+		if (i != 0) 
+		{
+			result << ":";
+		}
+		result  << std::setfill('0') << std::setw(2) << (int)digest_data[i];
+	}
+	return result.str();
+}
+
+
+// LLSecAPIBasicHandler Class
+// Interface handler class for the various security storage handlers.
+
+// We read the file on construction, and write it on destruction.  This
+// means multiple processes cannot modify the datastore.
+LLSecAPIBasicHandler::LLSecAPIBasicHandler(const std::string& protected_data_file)
+{
+	mProtectedDataFilename = protected_data_file;
+	mProtectedDataMap = LLSD::emptyMap();
+	_readProtectedData();
+}
+
+LLSecAPIBasicHandler::LLSecAPIBasicHandler()
+{
+	std::string mProtectedDataFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+														  "bin_conf.dat");
+
+	mProtectedDataMap = LLSD::emptyMap();
+	_readProtectedData();
+}
+
+LLSecAPIBasicHandler::~LLSecAPIBasicHandler()
+{
+	_writeProtectedData();
+}
+
+void LLSecAPIBasicHandler::_readProtectedData()
+{	
+	// attempt to load the file into our map
+	LLPointer<LLSDParser> parser = new LLSDXMLParser();
+	
+	llifstream protected_data_stream(mProtectedDataFilename.c_str(), 
+									llifstream::binary);
+	if (!protected_data_stream.fail()) {
+		int offset;
+		U8 salt[STORE_SALT_SIZE];
+		U8 buffer[BUFFER_READ_SIZE];
+		U8 decrypted_buffer[BUFFER_READ_SIZE];
+		int decrypted_length;		
+		
+
+		// read in the salt and key
+		protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
+		offset = 0;
+		if (protected_data_stream.gcount() < STORE_SALT_SIZE)
+		{
+			throw LLProtectedDataException("Corrupt Protected Data Store");
+		}
+		
+		// totally lame.  As we're not using the OS level protected data, we need to
+		// at least obfuscate the data.  We do this by using a salt stored at the head of the file
+		// to encrypt the data, therefore obfuscating it from someone using simple existing tools.
+		// It would be better to use the password, but as this store
+		// will be used to store the SL password when the user decides to have SL remember it, 
+		// so we can't use that.  OS-dependent store implementations will use the OS password/storage 
+		// mechanisms and are considered to be more secure.
+		// We've a strong intent to move to OS dependent protected data stores.
+		
+
+		// read in the rest of the file.
+		EVP_CIPHER_CTX ctx;
+		EVP_CIPHER_CTX_init(&ctx);
+		EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL);
+		// allocate memory:
+		std::string decrypted_data;	
+		
+		while(protected_data_stream.good()) {
+			// read data as a block:
+			protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE);
+			
+			EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, 
+							  buffer, protected_data_stream.gcount());
+			decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount());
+		}
+		
+		// RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is
+		// no block padding.
+		EVP_CIPHER_CTX_cleanup(&ctx);
+		std::istringstream parse_stream(decrypted_data);
+		if (parser->parse(parse_stream, mProtectedDataMap, 
+						  LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
+		{
+			throw LLProtectedDataException("Corrupt Protected Data Store");
+		}
+	}
+}
+
+void LLSecAPIBasicHandler::_writeProtectedData()
+{	
+	std::ostringstream formatted_data_ostream;
+	U8 salt[STORE_SALT_SIZE];
+	U8 buffer[BUFFER_READ_SIZE];
+	U8 encrypted_buffer[BUFFER_READ_SIZE];
+	
+	if(mProtectedDataMap.isUndefined())
+	{
+		LLFile::remove(mProtectedDataFilename);
+		return;
+	}
+	// create a string with the formatted data.
+	LLSDSerialize::toXML(mProtectedDataMap, formatted_data_ostream);
+	
+	std::istringstream formatted_data_istream(formatted_data_ostream.str());
+	// generate the seed
+	RAND_bytes(salt, STORE_SALT_SIZE);
+	
+	// write to a temp file so we don't clobber the initial file if there is
+	// an error.
+	std::string tmp_filename = mProtectedDataFilename + ".tmp";
+	
+	llofstream protected_data_stream(tmp_filename.c_str(), 
+										llofstream::binary);
+	try
+	{
+		
+		EVP_CIPHER_CTX ctx;
+		EVP_CIPHER_CTX_init(&ctx);
+		EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
+		protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);	
+		while (formatted_data_istream.good())
+		{
+			formatted_data_istream.read((char *)buffer, BUFFER_READ_SIZE);
+			if(formatted_data_istream.gcount() == 0)
+			{
+				break;
+			}
+			int encrypted_length;
+			EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, 
+						  buffer, formatted_data_istream.gcount());
+			protected_data_stream.write((const char *)encrypted_buffer, encrypted_length);
+		}
+		
+		// no EVP_EncrypteFinal, as this is a stream cipher
+		EVP_CIPHER_CTX_cleanup(&ctx);
+
+		protected_data_stream.close();
+	}
+	catch (...)
+	{
+		// it's good practice to clean up any secure information on error
+		// (even though this file isn't really secure.  Perhaps in the future
+		// it may be, however.
+		LLFile::remove(tmp_filename);
+		throw LLProtectedDataException("Error writing Protected Data Store");
+	}
+
+	// move the temporary file to the specified file location.
+	if((LLFile::remove(mProtectedDataFilename) != 0) || 
+	   (LLFile::rename(tmp_filename, mProtectedDataFilename)))
+	{
+		LLFile::remove(tmp_filename);
+		throw LLProtectedDataException("Could not overwrite protected data store");
+	}
+}
+		
+// instantiate a certificate from a pem string
+LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(const std::string& pem_cert)
+{
+	LLPointer<LLCertificate> result = new LLBasicCertificate(pem_cert);
+	return result;
+}
+		
+
+		
+// instiate a certificate from an openssl X509 structure
+LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert)
+{
+	LLPointer<LLCertificate> result = new LLBasicCertificate(openssl_cert);
+	return result;		
+}
+		
+// instantiate a chain from an X509_STORE_CTX
+LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain)
+{
+	LLPointer<LLCertificateChain> result = NULL;
+	return result;
+}
+		
+// instantiate a cert store given it's id.  if a persisted version
+// exists, it'll be loaded.  If not, one will be created (but not
+// persisted)
+LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id)
+{
+	LLPointer<LLCertificateStore> result;
+	return result;
+}
+		
+// retrieve protected data
+LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type,
+											const std::string& data_id)
+{
+	if (mProtectedDataMap.has(data_type) && 
+		mProtectedDataMap[data_type].isMap() && 
+		mProtectedDataMap[data_type].has(data_id))
+	{
+		return mProtectedDataMap[data_type][data_id];
+	}
+																				
+	return LLSD();
+}
+
+// persist data in a protected store
+void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type,
+									  const std::string& data_id,
+									  const LLSD& data)
+{
+	if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) {
+		mProtectedDataMap[data_type] = LLSD::emptyMap();
+	}
+	
+	mProtectedDataMap[data_type][data_id] = data; 
+}
\ No newline at end of file
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
new file mode 100644
index 0000000000..0ec6938583
--- /dev/null
+++ b/indra/newview/llsechandler_basic.h
@@ -0,0 +1,116 @@
+/** 
+ * @file llsechandler_basic.h
+ * @brief Security API for services such as certificate handling
+ * secure local storage, etc.
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LLSECHANDLER_BASIC
+#define LLSECHANDLER_BASIC
+
+#include "llsecapi.h"
+#include <vector>
+#include <openssl/x509.h>
+
+// helpers
+extern LLSD cert_name_from_X509_NAME(X509_NAME* name);
+extern std::string cert_string_name_from_X509_NAME(X509_NAME* name);
+extern std::string cert_string_from_asn1_integer(ASN1_INTEGER* value);
+extern LLDate cert_date_from_asn1_time(ASN1_TIME* asn1_time);
+extern std::string cert_get_digest(const std::string& digest_type, X509 *cert);
+
+
+// class LLCertificate
+// 
+class LLBasicCertificate : public LLCertificate
+{
+public:		
+	LOG_CLASS(LLBasicCertificate);
+
+	LLBasicCertificate(const std::string& pem_cert);
+	LLBasicCertificate(X509* openSSLX509);
+	
+	virtual ~LLBasicCertificate();
+	
+	virtual std::string getPem();
+	virtual std::vector<U8> getBinary();
+	virtual LLSD getLLSD();
+
+	virtual X509* getOpenSSLX509();
+protected:
+	// certificates are stored as X509 objects, as validation and
+	// other functionality is via openssl
+	X509* mCert;
+};
+
+// LLSecAPIBasicHandler Class
+// Interface handler class for the various security storage handlers.
+class LLSecAPIBasicHandler : public LLSecAPIHandler
+{
+public:
+	
+	LLSecAPIBasicHandler(const std::string& protected_data_filename);
+	LLSecAPIBasicHandler();
+	
+	virtual ~LLSecAPIBasicHandler();
+	
+	// instantiate a certificate from a pem string
+	virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert);
+	
+	
+	// instiate a certificate from an openssl X509 structure
+	virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert);
+	
+	// instantiate a chain from an X509_STORE_CTX
+	virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain);
+	
+	// instantiate a cert store given it's id.  if a persisted version
+	// exists, it'll be loaded.  If not, one will be created (but not
+	// persisted)
+	virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id);
+	
+	// persist data in a protected store
+	virtual void setProtectedData(const std::string& data_type,
+								  const std::string& data_id,
+								  const LLSD& data);
+	
+	// retrieve protected data
+	virtual LLSD getProtectedData(const std::string& data_type,
+								  const std::string& data_id);
+protected:
+	void _readProtectedData();
+	void _writeProtectedData();
+	
+	std::string mProtectedDataFilename;
+	LLSD mProtectedDataMap;
+};
+
+#endif // LLSECHANDLER_BASIC
+
+
+
-- 
GitLab