From 1ad46b5cd0fcac0d3224d37d555092258593eabd Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 May 2010 13:59:10 -0700 Subject: DEV-50173 - investigate certificate code performance DEV-50166 - LLBasicCertificateChain::validate calls in log Added caching of certificates that have been validated. The sha1 hash for the certificate is stored and is associated with the from and to times. When the certificate is validated, the code determines whether the certificate has successfully been validated before by looking for it in the cache, and then checks the date of the cert. If that is successful, the validation calls with success. Otherwise, it proceeds to do a full validation of the certificate. --- indra/newview/llsecapi.cpp | 2 +- indra/newview/llsecapi.h | 31 ++++--- indra/newview/llsechandler_basic.cpp | 114 +++++++++++++++++------- indra/newview/llsechandler_basic.h | 23 +++-- indra/newview/llstartup.cpp | 3 +- indra/newview/llxmlrpctransaction.cpp | 3 +- indra/newview/tests/llsechandler_basic_test.cpp | 34 +++---- 7 files changed, 134 insertions(+), 76 deletions(-) (limited to 'indra') diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 1caeec5b04..9e636f38c0 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -124,7 +124,7 @@ int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param) // we rely on libcurl to validate the hostname, as libcurl does more extensive validation // leaving our hostname validation call mechanism for future additions with respect to // OS native (Mac keyring, windows CAPI) validation. - chain->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), store, validation_params); + store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); } catch (LLCertValidationTrustException& cert_exception) { diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index 59a1e1eff0..5a1a3879d4 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -154,7 +154,7 @@ public: // return an LLSD object containing information about the certificate // such as its name, signature, expiry time, serial number - virtual LLSD getLLSD() const=0; + virtual void getLLSD(LLSD& llsd)=0; // return an openSSL X509 struct for the certificate virtual X509* getOpenSSLX509() const=0; @@ -231,6 +231,18 @@ public: virtual LLPointer erase(iterator cert)=0; }; +// class LLCertificateChain +// Class representing a chain of certificates in order, with the +// first element being the child cert. +class LLCertificateChain : virtual public LLCertificateVector +{ + +public: + LLCertificateChain() {} + + virtual ~LLCertificateChain() {} + +}; // class LLCertificateStore // represents a store of certificates, typically a store of root CA @@ -250,30 +262,17 @@ public: // return the store id virtual std::string storeId() const=0; -}; - -// class LLCertificateChain -// Class representing a chain of certificates in order, with the -// first element being the child cert. -class LLCertificateChain : virtual public LLCertificateVector -{ - -public: - LLCertificateChain() {} - virtual ~LLCertificateChain() {} - // validate a certificate chain given the params. // Will throw exceptions on error virtual void validate(int validation_policy, - LLPointer ca_store, + LLPointer cert_chain, const LLSD& validation_params) =0; + }; - - inline bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) { diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index edf5ce9b60..84ab9b9175 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -85,7 +85,6 @@ LLBasicCertificate::LLBasicCertificate(const std::string& pem_cert) { throw LLInvalidCertificate(this); } - _initLLSD(); } @@ -96,7 +95,6 @@ LLBasicCertificate::LLBasicCertificate(X509* pCert) throw LLInvalidCertificate(this); } mCert = X509_dup(pCert); - _initLLSD(); } LLBasicCertificate::~LLBasicCertificate() @@ -150,9 +148,13 @@ std::vector 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 +518,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++) @@ -543,7 +546,8 @@ LLBasicCertificateVector::iterator LLBasicCertificateVector::find(const LLSD& pa void LLBasicCertificateVector::insert(iterator _iter, LLPointer 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(); @@ -691,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 @@ -850,12 +855,13 @@ bool _LLSDArrayIncludesValue(const LLSD& llsd_set, LLSD llsd_value) } void _validateCert(int validation_policy, - const LLPointer cert, + LLPointer 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)) { @@ -943,8 +949,9 @@ bool _verify_signature(LLPointer parent, LLPointer 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)) @@ -979,6 +986,7 @@ bool _verify_signature(LLPointer 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 @@ -993,8 +1001,8 @@ bool _verify_signature(LLPointer 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 ca_store, +void LLBasicCertificateStore::validate(int validation_policy, + LLPointer cert_chain, const LLSD& validation_params) { @@ -1002,8 +1010,8 @@ void LLBasicCertificateChain::validate(int validation_policy, { 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)) { @@ -1012,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"); @@ -1021,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())) @@ -1030,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 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 | @@ -1061,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(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]; @@ -1087,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), @@ -1105,11 +1147,16 @@ void LLBasicCertificateChain::validate(int validation_policy, throw LLCertValidationInvalidSignatureException(*current_cert); } // successfully validated. + mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); return; } previous_cert = (*current_cert); current_cert++; - depth++; + depth++; + if(current_cert != current_cert != cert_chain->end()) + { + (*current_cert)->getLLSD(current_cert_info); + } } if (validation_policy & VALIDATION_POLICY_TRUSTED) { @@ -1118,6 +1165,7 @@ void LLBasicCertificateChain::validate(int validation_policy, throw LLCertValidationTrustException((*this)[size()-1]); } + mTrustedCertCache[sha1_hash] = std::pair(from_time, to_time); } @@ -1155,7 +1203,7 @@ void LLSecAPIBasicHandler::init() "CA.pem"); - LL_INFOS("SECAPI") << "Loading certificate store from " << store_file << LL_ENDL; + 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 @@ -1465,7 +1513,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer 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? diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index 4bbb73f062..3ddd36a81a 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -59,12 +59,13 @@ public: virtual std::string getPem() const; virtual std::vector getBinary() const; - virtual LLSD getLLSD() const; + virtual void getLLSD(LLSD &llsd); virtual X509* getOpenSSLX509() const; // set llsd elements for testing void setLLSD(const std::string name, const LLSD& value) { mLLSDInfo[name] = value; } + protected: // certificates are stored as X509 objects, as validation and @@ -173,8 +174,21 @@ public: // return the store id virtual std::string storeId() const; + // validate a certificate chain against a certificate store, using the + // given validation policy. + virtual void validate(int validation_policy, + LLPointer ca_chain, + const LLSD& validation_params); + protected: - std::vector >mCerts; + std::vector > mCerts; + + // cache of cert sha1 hashes to from/to date pairs, to improve + // performance of cert trust. Note, these are not the CA certs, + // but the certs that have been validated against this store. + typedef std::map > t_cert_cache; + t_cert_cache mTrustedCertCache; + std::string mFilename; }; @@ -189,11 +203,6 @@ public: virtual ~LLBasicCertificateChain() {} - // validate a certificate chain against a certificate store, using the - // given validation policy. - virtual void validate(int validation_policy, - LLPointer ca_store, - const LLSD& validation_params); }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0a464b3b6c..7022d83868 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2702,7 +2702,8 @@ LLSD transform_cert_args(LLPointer cert) { LLSD args = LLSD::emptyMap(); std::string value; - LLSD cert_info = cert->getLLSD(); + LLSD cert_info; + cert->getLLSD(cert_info); // convert all of the elements in the cert into // args for the xml dialog, so we have flexability to // display various parts of the cert by only modifying diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index da61840761..bc1a48e26a 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -247,7 +247,8 @@ int LLXMLRPCTransaction::Impl::_sslCertVerifyCallback(X509_STORE_CTX *ctx, void validation_params[CERT_HOSTNAME] = uri.hostName(); try { - chain->validate(VALIDATION_POLICY_SSL, store, validation_params); + // don't validate hostname. Let libcurl do it instead. That way, it'll handle redirects + store->validate(VALIDATION_POLICY_SSL & (~VALIDATION_POLICY_HOSTNAME), chain, validation_params); } catch (LLCertValidationTrustException& cert_exception) { diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index fd680b24f0..d1330e2270 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -950,15 +950,15 @@ namespace tut test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // add the root certificate to the chain and revalidate test_chain->add(new LLBasicCertificate(mX509RootCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // add the child cert at the head of the chain, and revalidate (3 deep chain) test_chain->insert(test_chain->begin(), new LLBasicCertificate(mX509ChildCert)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // basic failure cases test_chain = new LLBasicCertificateChain(NULL); @@ -967,14 +967,14 @@ namespace tut ensure_throws("no CA, with only a child cert", LLCertValidationTrustException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TRUSTED, - test_store, + test_chain, validation_params); // validate without the trust flag. - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // clear out the store test_store = new LLBasicCertificateStore("mycertstore.pem"); @@ -983,9 +983,9 @@ namespace tut ensure_throws("no CA, with child and intermediate certs", LLCertValidationTrustException, (*test_chain)[1], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TRUSTED, - test_store, + test_chain, validation_params); // validate without the trust flag test_chain->validate(0, test_store, validation_params); @@ -994,7 +994,7 @@ namespace tut LLSD child_info = (*test_chain)[0]->getLLSD(); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() + 1.0); - test_chain->validate(VALIDATION_POLICY_TIME, test_store, validation_params); + test_store->validate(VALIDATION_POLICY_TIME, test_chain, validation_params); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = child_info[CERT_VALID_FROM].asDate(); @@ -1005,9 +1005,9 @@ namespace tut ensure_throws("Child cert not yet valid" , LLCertValidationExpirationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TIME, - test_store, + test_chain, validation_params); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_TO].asDate().secondsSinceEpoch() + 1.0); @@ -1016,9 +1016,9 @@ namespace tut ensure_throws("Child cert expired", LLCertValidationExpirationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_TIME, - test_store, + test_chain, validation_params); // test SSL KU @@ -1026,7 +1026,7 @@ namespace tut test_chain = new LLBasicCertificateChain(NULL); test_chain->add(new LLBasicCertificate(mX509ChildCert)); test_chain->add(new LLBasicCertificate(mX509IntermediateCert)); - test_chain->validate(VALIDATION_POLICY_SSL_KU, test_store, validation_params); + test_store->validate(VALIDATION_POLICY_SSL_KU, test_chain, validation_params); test_chain = new LLBasicCertificateChain(NULL); test_chain->add(new LLBasicCertificate(mX509TestCert)); @@ -1034,9 +1034,9 @@ namespace tut ensure_throws("Cert doesn't have ku", LLCertKeyUsageValidationException, (*test_chain)[0], - test_chain->validate, + test_store->validate, VALIDATION_POLICY_SSL_KU, - test_store, + test_chain, validation_params); // test sha1RSA validation @@ -1044,7 +1044,7 @@ namespace tut test_chain->add(new LLBasicCertificate(mSha1RSATestCert)); test_chain->add(new LLBasicCertificate(mSha1RSATestCA)); - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); } }; -- cgit v1.2.3 From a7d1c68c787fcccf888632b9787c4cc9b30393f7 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 May 2010 15:31:10 -0700 Subject: Fixup some certificate related unit tests --- indra/newview/llsechandler_basic.cpp | 2 +- indra/newview/tests/llsechandler_basic_test.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 84ab9b9175..a81cde3126 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1153,7 +1153,7 @@ void LLBasicCertificateStore::validate(int validation_policy, previous_cert = (*current_cert); current_cert++; depth++; - if(current_cert != current_cert != cert_chain->end()) + if(current_cert != cert_chain->end()) { (*current_cert)->getLLSD(current_cert_info); } diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index d1330e2270..dfbd596d39 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -328,7 +328,8 @@ namespace tut ensure_equals("Der Format is correct", memcmp(buffer, mDerFormat.c_str(), mDerFormat.length()), 0); - LLSD llsd_cert = test_cert->getLLSD(); + LLSD llsd_cert; + test_cert->getLLSD(llsd_cert); std::ostringstream llsd_value; llsd_value << LLSDOStreamer(llsd_cert) << std::endl; std::string llsd_cert_str = llsd_value.str(); @@ -988,10 +989,11 @@ namespace tut test_chain, validation_params); // validate without the trust flag - test_chain->validate(0, test_store, validation_params); + test_store->validate(0, test_chain, validation_params); // Test time validity - LLSD child_info = (*test_chain)[0]->getLLSD(); + LLSD child_info; + ((*test_chain)[0])->getLLSD(child_info); validation_params = LLSD::emptyMap(); validation_params[CERT_VALIDATION_DATE] = LLDate(child_info[CERT_VALID_FROM].asDate().secondsSinceEpoch() + 1.0); test_store->validate(VALIDATION_POLICY_TIME, test_chain, validation_params); -- cgit v1.2.3 From 32ad37b3f7ca48564bd15de2664f323ad4a2d367 Mon Sep 17 00:00:00 2001 From: Roxie Linden Date: Mon, 24 May 2010 16:21:29 -0700 Subject: Few more touchups for the cert performance code --- indra/newview/llsechandler_basic.cpp | 5 ++--- indra/newview/tests/llsechandler_basic_test.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index a81cde3126..5f24d4398a 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -1006,7 +1006,7 @@ void LLBasicCertificateStore::validate(int validation_policy, const LLSD& validation_params) { - if(size() < 1) + if(cert_chain->size() < 1) { throw LLCertException(NULL, "No certs in chain"); } @@ -1160,9 +1160,8 @@ void LLBasicCertificateStore::validate(int validation_policy, } if (validation_policy & VALIDATION_POLICY_TRUSTED) { - LLPointer 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(from_time, to_time); diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index dfbd596d39..df0673a159 100644 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -963,8 +963,15 @@ namespace tut // basic failure cases test_chain = new LLBasicCertificateChain(NULL); - //validate with only the child cert + //validate with only the child cert in chain, but child cert was previously + // trusted test_chain->add(new LLBasicCertificate(mX509ChildCert)); + + // validate without the trust flag. + test_store->validate(VALIDATION_POLICY_TRUSTED, test_chain, validation_params); + + // Validate with child cert but no parent, and no parent in CA store + test_store = new LLBasicCertificateStore("mycertstore.pem"); ensure_throws("no CA, with only a child cert", LLCertValidationTrustException, (*test_chain)[0], @@ -1033,6 +1040,7 @@ namespace tut test_chain = new LLBasicCertificateChain(NULL); test_chain->add(new LLBasicCertificate(mX509TestCert)); + test_store = new LLBasicCertificateStore("mycertstore.pem"); ensure_throws("Cert doesn't have ku", LLCertKeyUsageValidationException, (*test_chain)[0], -- cgit v1.2.3 From cca5aa48ae07a2d0e4f4a26e647b360c098cd831 Mon Sep 17 00:00:00 2001 From: karina Date: Wed, 26 May 2010 23:46:42 -0700 Subject: Add new mechanism for getting a unique machine id. --- indra/newview/CMakeLists.txt | 2 + indra/newview/llappviewer.cpp | 2 + indra/newview/llmachineid.cpp | 267 +++++++++++++++++++++ indra/newview/llmachineid.h | 56 +++++ indra/newview/llsechandler_basic.cpp | 19 +- indra/newview/llxmlrpctransaction.cpp | 6 +- .../newview/skins/default/xui/en/notifications.xml | 31 +++ indra/newview/tests/llsechandler_basic_test.cpp | 15 +- 8 files changed, 380 insertions(+), 18 deletions(-) create mode 100644 indra/newview/llmachineid.cpp create mode 100644 indra/newview/llmachineid.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d77d53f6af..ec0116bd87 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -272,6 +272,7 @@ set(viewer_SOURCE_FILES lllogchat.cpp llloginhandler.cpp lllogininstance.cpp + llmachineid.cpp llmanip.cpp llmaniprotate.cpp llmanipscale.cpp @@ -787,6 +788,7 @@ set(viewer_HEADER_FILES lllogchat.h llloginhandler.h lllogininstance.h + llmachineid.h llmanip.h llmaniprotate.h llmanipscale.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f7f7cb599e..5756eade87 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -195,6 +195,7 @@ // Include for security api initialization #include "llsecapi.h" +#include "llmachineid.h" // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either @@ -619,6 +620,7 @@ bool LLAppViewer::init() // *NOTE:Mani - LLCurl::initClass is not thread safe. // Called before threads are created. LLCurl::initClass(); + LLMachineID::init(); initThreads(); writeSystemInfo(); diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp new file mode 100644 index 0000000000..b691baaf08 --- /dev/null +++ b/indra/newview/llmachineid.cpp @@ -0,0 +1,267 @@ +/** + * @file llmachineid.cpp + * @brief retrieves unique machine ids + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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 "lluuid.h" +#include "llmachineid.h" +#define _WIN32_DCOM +#include +using namespace std; +#include +#include + +unsigned char static_unique_id[] = {0,0,0,0,0,0}; +bool static has_static_unique_id = false; + +// get an unique machine id. +// NOT THREAD SAFE - do before setting up threads. +// MAC Address doesn't work for Windows 7 since the first returned hardware MAC address changes with each reboot, Go figure?? + +S32 LLMachineID::init() +{ + memset(static_unique_id,0,sizeof(static_unique_id)); + size_t len = sizeof(static_unique_id); + S32 ret_code = 0; +#if LL_WINDOWS +# pragma comment(lib, "wbemuuid.lib") + + // algorithm to detect BIOS serial number found at: + // http://msdn.microsoft.com/en-us/library/aa394077%28VS.85%29.aspx + // we can't use the MAC address since on Windows 7, the first returned MAC address changes with every reboot. + + + HRESULT hres; + + // Step 1: -------------------------------------------------- + // Initialize COM. ------------------------------------------ + + hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hex << hres << LL_ENDL; + return 1; // Program has failed. + } + + // Step 2: -------------------------------------------------- + // Set general COM security levels -------------------------- + // Note: If you are using Windows 2000, you need to specify - + // the default authentication credentials for a user by using + // a SOLE_AUTHENTICATION_LIST structure in the pAuthList ---- + // parameter of CoInitializeSecurity ------------------------ + + hres = CoInitializeSecurity( + NULL, + -1, // COM authentication + NULL, // Authentication services + NULL, // Reserved + RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication + RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation + NULL, // Authentication info + EOAC_NONE, // Additional capabilities + NULL // Reserved + ); + + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Failed to initialize security. Error code = 0x" << hex << hres << LL_ENDL; + CoUninitialize(); + return 1; // Program has failed. + } + + // Step 3: --------------------------------------------------- + // Obtain the initial locator to WMI ------------------------- + + IWbemLocator *pLoc = NULL; + + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *) &pLoc); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Failed to create IWbemLocator object." << " Err code = 0x" << hex << hres << LL_ENDL; + CoUninitialize(); + return 1; // Program has failed. + } + + // Step 4: ----------------------------------------------------- + // Connect to WMI through the IWbemLocator::ConnectServer method + + IWbemServices *pSvc = NULL; + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (e.g. Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Could not connect. Error code = 0x" << hex << hres << LL_ENDL; + pLoc->Release(); + CoUninitialize(); + return 1; // Program has failed. + } + + LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; + + + // Step 5: -------------------------------------------------- + // Set security levels on the proxy ------------------------- + + hres = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hex << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return 1; // Program has failed. + } + + // Step 6: -------------------------------------------------- + // Use the IWbemServices pointer to make requests of WMI ---- + + // For example, get the name of the operating system + IEnumWbemClassObject* pEnumerator = NULL; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_OperatingSystem"), + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hex << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return 1; // Program has failed. + } + + // Step 7: ------------------------------------------------- + // Get the data from the query in step 6 ------------------- + + IWbemClassObject *pclsObj = NULL; + ULONG uReturn = 0; + + while (pEnumerator) + { + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if(0 == uReturn) + { + break; + } + + VARIANT vtProp; + + // Get the value of the Name property + hr = pclsObj->Get(L"SerialNumber", 0, &vtProp, 0, 0); + LL_DEBUGS("AppInit") << " Serial Number : " << vtProp.bstrVal << LL_ENDL; + // use characters in the returned Serial Number to create a byte array of size len + BSTR serialNumber ( vtProp.bstrVal); + unsigned int j = 0; + while( vtProp.bstrVal[j] != 0) + { + for (unsigned int i = 0; i < len; i++) + { + if (vtProp.bstrVal[j] == 0) + break; + + static_unique_id[i] = (unsigned int)(static_unique_id[i] + serialNumber[j]); + j++; + } + } + VariantClear(&vtProp); + + pclsObj->Release(); + pclsObj = NULL; + break; + } + + // Cleanup + // ======== + + if (pSvc) + pSvc->Release(); + if (pLoc) + pLoc->Release(); + if (pEnumerator) + pEnumerator->Release(); + CoUninitialize(); + ret_code=0; +#else + ret_code = LLUUID::getNodeID(&static_unique_id); +#endif + has_static_unique_id = true; + return ret_code; +} + + +S32 LLMachineID::getUniqueID(unsigned char *unique_id, size_t len) +{ + if (has_static_unique_id) + { + memcpy ( unique_id, &static_unique_id, len); + LL_DEBUGS("AppInit") << "UniqueID: " << unique_id[0] << unique_id[1]<< unique_id[2] << unique_id[3] << unique_id[4] << unique_id [5] << LL_ENDL; + return 1; + } + return 0; +} + + + + diff --git a/indra/newview/llmachineid.h b/indra/newview/llmachineid.h new file mode 100644 index 0000000000..8160309b47 --- /dev/null +++ b/indra/newview/llmachineid.h @@ -0,0 +1,56 @@ +/** + * @file llmachineid.h + * @brief retrieves unique machine ids + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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 LL_LLMACHINEID_H +#define LL_LLMACHINEID_H + + +class LLMachineID +{ +public: + LLMachineID(); + virtual ~LLMachineID(); + static S32 getUniqueID(unsigned char *unique_id, size_t len); + static S32 init(); + +protected: + +private: + + +}; + + + + + +#endif // LL_LLMACHINEID_H diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index edf5ce9b60..c006f4dd0d 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -52,6 +52,7 @@ LLS * By copying, modifying or distributing this software, you acknowledge #include #include #include +#include "llmachineid.h" @@ -1195,9 +1196,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); @@ -1281,9 +1282,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); @@ -1501,9 +1502,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()); diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index da61840761..58ba9e1378 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -514,7 +514,9 @@ void LLXMLRPCTransaction::Impl::setStatus(EStatus status, "Despite our best efforts, something unexpected has gone wrong. \n" " \n" "Please check secondlife.com/status \n" - "to see if there is a known problem with the service."; + "to see if there is a known problem with the service.\n" + "If you continue to experience problems," + "Please check your network and firewall setup.\n"; mStatusURI = "http://secondlife.com/status/"; } @@ -550,7 +552,7 @@ void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) "Often this means that your computer\'s clock is set incorrectly.\n" "Please go to Control Panels and make sure the time and date\n" "are set correctly.\n" - "\n" + "Also check that your network and firewall are setup correctly.\n" "If you continue to receive this error, please go\n" "to the Support section of the SecondLife.com web site\n" "and report the problem."; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 999f804e71..b9aec7dd63 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -6182,6 +6182,37 @@ Avatar '[NAME]' entered appearance mode. Avatar '[NAME]' left appearance mode. + + We're having trouble connecting using [PROTOCOL] [HOSTID]. + Please check your network and firewall setup. +
+