Skip to content
Snippets Groups Projects
Commit 1a9d19d9 authored by Roxanne Skelly's avatar Roxanne Skelly
Browse files
parent 78cb4204
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,7 @@ include(Boost) ...@@ -7,6 +7,7 @@ include(Boost)
include(BuildVersion) include(BuildVersion)
include(DBusGlib) include(DBusGlib)
include(DirectX) include(DirectX)
include(OpenSSL)
include(ELFIO) include(ELFIO)
include(FMOD) include(FMOD)
include(OPENAL) include(OPENAL)
...@@ -372,6 +373,8 @@ set(viewer_SOURCE_FILES ...@@ -372,6 +373,8 @@ set(viewer_SOURCE_FILES
llscrollingpanelparam.cpp llscrollingpanelparam.cpp
llsearchcombobox.cpp llsearchcombobox.cpp
llsearchhistory.cpp llsearchhistory.cpp
llsecapi.cpp
llsechandler_basic.cpp
llselectmgr.cpp llselectmgr.cpp
llsidepanelappearance.cpp llsidepanelappearance.cpp
llsidepanelinventory.cpp llsidepanelinventory.cpp
...@@ -875,6 +878,8 @@ set(viewer_HEADER_FILES ...@@ -875,6 +878,8 @@ set(viewer_HEADER_FILES
llscrollingpanelparam.h llscrollingpanelparam.h
llsearchcombobox.h llsearchcombobox.h
llsearchhistory.h llsearchhistory.h
llsecapi.h
llsechandler_basic.h
llselectmgr.h llselectmgr.h
llsidepanelappearance.h llsidepanelappearance.h
llsidepanelinventory.h llsidepanelinventory.h
...@@ -1618,6 +1623,8 @@ target_link_libraries(${VIEWER_BINARY_NAME} ...@@ -1618,6 +1623,8 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${WINDOWS_LIBRARIES} ${WINDOWS_LIBRARIES}
${XMLRPCEPI_LIBRARIES} ${XMLRPCEPI_LIBRARIES}
${ELFIO_LIBRARIES} ${ELFIO_LIBRARIES}
${OPENSSL_LIBRARIES}
${CRYPTO_LIBRARIES}
${LLLOGIN_LIBRARIES} ${LLLOGIN_LIBRARIES}
${GOOGLE_PERFTOOLS_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES}
) )
...@@ -1803,6 +1810,9 @@ if (LL_TESTS) ...@@ -1803,6 +1810,9 @@ if (LL_TESTS)
#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer) #ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
#ADD_VIEWER_BUILD_TEST(lltexturestatsuploader 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) endif (LL_TESTS)
/**
* @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;
}
/**
* @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
/**
* @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
/**
* @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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment