diff options
Diffstat (limited to 'indra/newview/llsechandler_basic.cpp')
-rw-r--r-- | indra/newview/llsechandler_basic.cpp | 224 |
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()); |