summaryrefslogtreecommitdiff
path: root/indra/newview/llsechandler_basic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llsechandler_basic.cpp')
-rw-r--r--indra/newview/llsechandler_basic.cpp224
1 files changed, 136 insertions, 88 deletions
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index df55ccf142..90e8ff0aae 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -3,30 +3,25 @@
* @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.
- *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
* 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
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * 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
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
-LLS * 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -52,6 +47,7 @@ LLS * By copying, modifying or distributing this software, you acknowledge
#include <iostream>
#include <iomanip>
#include <time.h>
+#include "llmachineid.h"
@@ -85,7 +81,6 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert)
{
throw LLInvalidCertificate(this);
}
- _initLLSD();
}
@@ -96,7 +91,6 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert)
throw LLInvalidCertificate(this);
}
mCert = X509_dup(pCert);
- _initLLSD();
}
LLBasicCertificate::~LLBasicCertificate()
@@ -150,9 +144,13 @@ std::vector<U8> LLBasicCertificate::getBinary() const
}
-LLSD LLBasicCertificate::getLLSD() const
+void LLBasicCertificate::getLLSD(LLSD &llsd)
{
- return mLLSDInfo;
+ if (mLLSDInfo.isUndefined())
+ {
+ _initLLSD();
+ }
+ llsd = mLLSDInfo;
}
// Initialize the LLSD info for the certificate
@@ -516,8 +514,9 @@ LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& pa
cert++)
{
- found= TRUE;
- LLSD cert_info = (*cert)->getLLSD();
+ found= TRUE;
+ LLSD cert_info;
+ (*cert)->getLLSD(cert_info);
for (LLSD::map_const_iterator param = params.beginMap();
param != params.endMap();
param++)
@@ -541,9 +540,10 @@ LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& pa
// Insert a certificate into the store. If the certificate already
// exists in the store, nothing is done.
void LLBasicCertificateVector::insert(iterator _iter,
- LLPointer<LLCertificate> cert)
+ LLPointer<LLCertificate> cert)
{
- LLSD cert_info = cert->getLLSD();
+ LLSD cert_info;
+ cert->getLLSD(cert_info);
if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST))
{
LLSD existing_cert_info = LLSD::emptyMap();
@@ -551,7 +551,11 @@ void LLBasicCertificateVector::insert(iterator _iter,
if(find(existing_cert_info) == end())
{
BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get());
- mCerts.insert(basic_iter->mIter, cert);
+ llassert(basic_iter);
+ if (basic_iter)
+ {
+ mCerts.insert(basic_iter->mIter, cert);
+ }
}
}
}
@@ -585,6 +589,11 @@ LLBasicCertificateStore::LLBasicCertificateStore(const std::string& filename)
void LLBasicCertificateStore::load_from_file(const std::string& filename)
{
// scan the PEM file extracting each certificate
+ if (!LLFile::isfile(filename))
+ {
+ return;
+ }
+
BIO* file_bio = BIO_new(BIO_s_file());
if(file_bio)
{
@@ -686,7 +695,8 @@ LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store)
while(untrusted_certs.size() > 0)
{
LLSD find_data = LLSD::emptyMap();
- LLSD cert_data = current->getLLSD();
+ LLSD cert_data;
+ current->getLLSD(cert_data);
// we simply build the chain via subject/issuer name as the
// client should not have passed in multiple CA's with the same
// subject name. If they did, it'll come out in the wash during
@@ -845,12 +855,13 @@ bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value)
}
void _validateCert(int validation_policy,
- const LLPointer<LLCertificate> cert,
+ LLPointer<LLCertificate> cert,
const LLSD& validation_params,
int depth)
{
- LLSD current_cert_info = cert->getLLSD();
+ LLSD current_cert_info;
+ cert->getLLSD(current_cert_info);
// check basic properties exist in the cert
if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING))
{
@@ -938,8 +949,9 @@ bool _verify_signature(LLPointer<LLCertificate> parent,
LLPointer<LLCertificate> child)
{
bool verify_result = FALSE;
- LLSD cert1 = parent->getLLSD();
- LLSD cert2 = child->getLLSD();
+ LLSD cert1, cert2;
+ parent->getLLSD(cert1);
+ child->getLLSD(cert2);
X509 *signing_cert = parent->getOpenSSLX509();
X509 *child_cert = child->getOpenSSLX509();
if((signing_cert != NULL) && (child_cert != NULL))
@@ -974,6 +986,7 @@ bool _verify_signature(LLPointer<LLCertificate> parent,
return verify_result;
}
+
// validate the certificate chain against a store.
// There are many aspects of cert validatioin policy involved in
// trust validation. The policies in this validation algorithm include
@@ -988,17 +1001,17 @@ bool _verify_signature(LLPointer<LLCertificate> parent,
// and verify the last cert is in the certificate store, or points
// to a cert in the store. It validates whether any cert in the chain
// is trusted in the store, even if it's not the last one.
-void LLBasicCertificateChain::validate(int validation_policy,
- LLPointer<LLCertificateStore> ca_store,
+void LLBasicCertificateStore::validate(int validation_policy,
+ LLPointer<LLCertificateChain> cert_chain,
const LLSD& validation_params)
{
- if(size() < 1)
+ if(cert_chain->size() < 1)
{
throw LLCertException(NULL, "No certs in chain");
}
- iterator current_cert = begin();
- LLSD current_cert_info = (*current_cert)->getLLSD();
+ iterator current_cert = cert_chain->begin();
+ LLSD current_cert_info;
LLSD validation_date;
if (validation_params.has(CERT_VALIDATION_DATE))
{
@@ -1007,6 +1020,7 @@ void LLBasicCertificateChain::validate(int validation_policy,
if (validation_policy & VALIDATION_POLICY_HOSTNAME)
{
+ (*current_cert)->getLLSD(current_cert_info);
if(!validation_params.has(CERT_HOSTNAME))
{
throw LLCertException((*current_cert), "No hostname passed in for validation");
@@ -1016,7 +1030,7 @@ void LLBasicCertificateChain::validate(int validation_policy,
throw LLInvalidCertificate((*current_cert));
}
- LL_INFOS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() <<
+ LL_DEBUGS("SECAPI") << "Validating the hostname " << validation_params[CERT_HOSTNAME].asString() <<
"against the cert CN " << current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString() << LL_ENDL;
if(!_cert_hostname_wildcard_match(validation_params[CERT_HOSTNAME].asString(),
current_cert_info[CERT_SUBJECT_NAME][CERT_NAME_CN].asString()))
@@ -1025,16 +1039,50 @@ void LLBasicCertificateChain::validate(int validation_policy,
(*current_cert));
}
}
-
+ // check the cache of already validated certs
+ X509* cert_x509 = (*current_cert)->getOpenSSLX509();
+ if(!cert_x509)
+ {
+ throw LLInvalidCertificate((*current_cert));
+ }
+ std::string sha1_hash((const char *)cert_x509->sha1_hash, SHA_DIGEST_LENGTH);
+ t_cert_cache::iterator cache_entry = mTrustedCertCache.find(sha1_hash);
+ if(cache_entry != mTrustedCertCache.end())
+ {
+ LL_DEBUGS("SECAPI") << "Found cert in cache" << LL_ENDL;
+ // this cert is in the cache, so validate the time.
+ if (validation_policy & VALIDATION_POLICY_TIME)
+ {
+ LLDate validation_date(time(NULL));
+ if(validation_params.has(CERT_VALIDATION_DATE))
+ {
+ validation_date = validation_params[CERT_VALIDATION_DATE];
+ }
+
+ if((validation_date < cache_entry->second.first) ||
+ (validation_date > cache_entry->second.second))
+ {
+ throw LLCertValidationExpirationException((*current_cert), validation_date);
+ }
+ }
+ // successfully found in cache
+ return;
+ }
+ if(current_cert_info.isUndefined())
+ {
+ (*current_cert)->getLLSD(current_cert_info);
+ }
+ LLDate from_time = current_cert_info[CERT_VALID_FROM].asDate();
+ LLDate to_time = current_cert_info[CERT_VALID_TO].asDate();
int depth = 0;
LLPointer<LLCertificate> previous_cert;
// loop through the cert chain, validating the current cert against the next one.
- while(current_cert != end())
+ while(current_cert != cert_chain->end())
{
int local_validation_policy = validation_policy;
- if(current_cert == begin())
+ if(current_cert == cert_chain->begin())
{
// for the child cert, we don't validate CA stuff
local_validation_policy &= ~(VALIDATION_POLICY_CA_KU |
@@ -1056,23 +1104,23 @@ void LLBasicCertificateChain::validate(int validation_policy,
depth);
// look for a CA in the CA store that may belong to this chain.
- LLSD cert_llsd = (*current_cert)->getLLSD();
LLSD cert_search_params = LLSD::emptyMap();
// is the cert itself in the store?
- cert_search_params[CERT_SHA1_DIGEST] = cert_llsd[CERT_SHA1_DIGEST];
- LLCertificateStore::iterator found_store_cert = ca_store->find(cert_search_params);
- if(found_store_cert != ca_store->end())
+ cert_search_params[CERT_SHA1_DIGEST] = current_cert_info[CERT_SHA1_DIGEST];
+ LLCertificateStore::iterator found_store_cert = find(cert_search_params);
+ if(found_store_cert != end())
{
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
return;
}
// is the parent in the cert store?
cert_search_params = LLSD::emptyMap();
- cert_search_params[CERT_SUBJECT_NAME_STRING] = cert_llsd[CERT_ISSUER_NAME_STRING];
- if (cert_llsd.has(CERT_AUTHORITY_KEY_IDENTIFIER))
+ cert_search_params[CERT_SUBJECT_NAME_STRING] = current_cert_info[CERT_ISSUER_NAME_STRING];
+ if (current_cert_info.has(CERT_AUTHORITY_KEY_IDENTIFIER))
{
- LLSD cert_aki = cert_llsd[CERT_AUTHORITY_KEY_IDENTIFIER];
+ LLSD cert_aki = current_cert_info[CERT_AUTHORITY_KEY_IDENTIFIER];
if(cert_aki.has(CERT_AUTHORITY_KEY_IDENTIFIER_ID))
{
cert_search_params[CERT_SUBJECT_KEY_IDENTFIER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_ID];
@@ -1082,11 +1130,10 @@ void LLBasicCertificateChain::validate(int validation_policy,
cert_search_params[CERT_SERIAL_NUMBER] = cert_aki[CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL];
}
}
- found_store_cert = ca_store->find(cert_search_params);
+ found_store_cert = find(cert_search_params);
- if(found_store_cert != ca_store->end())
+ if(found_store_cert != end())
{
- LLSD foo = (*found_store_cert)->getLLSD();
// validate the store cert against the depth
_validateCert(validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS,
(*found_store_cert),
@@ -1100,19 +1147,24 @@ void LLBasicCertificateChain::validate(int validation_policy,
throw LLCertValidationInvalidSignatureException(*current_cert);
}
// successfully validated.
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
return;
}
previous_cert = (*current_cert);
current_cert++;
- depth++;
+ depth++;
+ if(current_cert != cert_chain->end())
+ {
+ (*current_cert)->getLLSD(current_cert_info);
+ }
}
if (validation_policy & VALIDATION_POLICY_TRUSTED)
{
- LLPointer<LLCertificate> untrusted_ca_cert = (*this)[size()-1];
// we reached the end without finding a trusted cert.
- throw LLCertValidationTrustException((*this)[size()-1]);
+ throw LLCertValidationTrustException((*cert_chain)[cert_chain->size()-1]);
}
+ mTrustedCertCache[sha1_hash] = std::pair<LLDate, LLDate>(from_time, to_time);
}
@@ -1148,30 +1200,26 @@ void LLSecAPIBasicHandler::init()
"bin_conf.dat");
std::string store_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
"CA.pem");
- // copy the CA file to a user writable location so we can manipulate it.
- // for this provider, by using a user writable file, there is a risk that
- // an attacking program can modify the file, but OS dependent providers
- // will reduce that risk.
- // by using a user file, modifications will be limited to one user if
- // we read-only the main file
- if (!LLFile::isfile(store_file))
+
+
+ LL_DEBUGS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL;
+ mStore = new LLBasicCertificateStore(store_file);
+
+ // grab the application CA.pem file that contains the well-known certs shipped
+ // with the product
+ std::string ca_file_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
+ llinfos << "app path " << ca_file_path << llendl;
+ LLBasicCertificateStore app_ca_store = LLBasicCertificateStore(ca_file_path);
+
+ // push the applicate CA files into the store, therefore adding any new CA certs that
+ // updated
+ for(LLCertificateVector::iterator i = app_ca_store.begin();
+ i != app_ca_store.end();
+ i++)
{
-
- std::string ca_file_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
- llifstream ca_file(ca_file_path.c_str(), llifstream::binary | llifstream::in);
- llofstream copied_store_file(store_file.c_str(), llofstream::binary | llofstream::out);
-
- while(!ca_file.fail())
- {
- char buffer[BUFFER_READ_SIZE];
- ca_file.read(buffer, sizeof(buffer));
- copied_store_file.write(buffer, ca_file.gcount());
- }
- ca_file.close();
- copied_store_file.close();
+ mStore->add(*i);
}
- LL_INFOS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL;
- mStore = new LLBasicCertificateStore(store_file);
+
}
_readProtectedData(); // initialize mProtectedDataMap
// may throw LLProtectedDataException if saved datamap is not decryptable
@@ -1194,9 +1242,9 @@ void LLSecAPIBasicHandler::_readProtectedData()
U8 buffer[BUFFER_READ_SIZE];
U8 decrypted_buffer[BUFFER_READ_SIZE];
int decrypted_length;
- unsigned char MACAddress[MAC_ADDRESS_BYTES];
- LLUUID::getNodeID(MACAddress);
- LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
// read in the salt and key
protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
@@ -1280,9 +1328,9 @@ void LLSecAPIBasicHandler::_writeProtectedData()
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
- unsigned char MACAddress[MAC_ADDRESS_BYTES];
- LLUUID::getNodeID(MACAddress);
- LLXORCipher cipher(MACAddress, MAC_ADDRESS_BYTES);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
cipher.encrypt(salt, STORE_SALT_SIZE);
protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);
@@ -1464,7 +1512,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav
{
credential["authenticator"] = cred->getAuthenticator();
}
- LL_INFOS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
+ LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
setProtectedData("credential", cred->getGrid(), credential);
//*TODO: If we're saving Agni credentials, should we write the
// credentials to the legacy password.dat/etc?
@@ -1500,9 +1548,9 @@ std::string LLSecAPIBasicHandler::_legacyLoadPassword()
}
// Decipher with MAC address
- unsigned char MACAddress[MAC_ADDRESS_BYTES];
- LLUUID::getNodeID(MACAddress);
- LLXORCipher cipher(MACAddress, 6);
+ unsigned char unique_id[MAC_ADDRESS_BYTES];
+ LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
+ LLXORCipher cipher(unique_id, sizeof(unique_id));
cipher.decrypt(&buffer[0], buffer.size());
return std::string((const char*)&buffer[0], buffer.size());