diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 81cbd3af28d854e2bb606aa6ce39af61ea83067a..ce01511f4e0524a1a17e7f4e6ac252b538298c80 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -7,6 +7,7 @@ include(00-Common) include(LLCommon) include(Linking) include(Boost) +include(OpenSSL) include(LLSharedLibs) include(GoogleBreakpad) include(GooglePerfTools) @@ -16,6 +17,7 @@ include(ZLIB) include_directories( ${EXPAT_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${BREAKPAD_INCLUDE_DIRECTORIES} ) @@ -260,6 +262,7 @@ target_link_libraries( ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} + ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} @@ -286,7 +289,7 @@ if (LL_TESTS) LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) - set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES}) + set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES} ${OPENSSL_LIBRARIES}) LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}") LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}") diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index a7f6a3a810304adaf28b7afbc8c73cf0412d5d29..cc116259080f09af503db8d9d7da3af5fe164080 100755 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -28,35 +28,30 @@ #include "linden_common.h" #include "llbase64.h" - +#include <openssl/evp.h> #include <string> -#include "apr_base64.h" - - // static std::string LLBase64::encode(const U8* input, size_t input_size) { - std::string output; - if (input - && input_size > 0) - { - // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(input_size); - char* b64_buffer = new char[b64_buffer_length]; - - // This is faster than apr_base64_encode() if you know - // you're not on an EBCDIC machine. Also, the output is - // null terminated, even though the documentation doesn't - // specify. See apr_base64.c for details. JC - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - input, - input_size); - output.assign(b64_buffer); - delete[] b64_buffer; - } - return output; + if (!(input && input_size > 0)) return LLStringUtil::null; + + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + BIO *bio = BIO_new(BIO_s_mem()); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_push(b64, bio); + BIO_write(bio, input, input_size); + + BIO_flush(bio); + + char *new_data; + size_t bytes_written = BIO_get_mem_data(bio, &new_data); + std::string result(new_data, bytes_written); + BIO_free_all(bio); + + return result; } // static @@ -72,13 +67,18 @@ std::string LLBase64::encode(const std::string& in_str) // static size_t LLBase64::decode(const std::string& input, U8 * buffer, size_t buffer_size) { - size_t len = apr_base64_decode_len(input.c_str()); - if (len != buffer_size || buffer_size <= 0 || buffer == 0 || input.empty()) - return 0; + if (input.empty()) return 0; + + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - len = apr_base64_decode_binary(buffer, input.c_str()); + // BIO_new_mem_buf is not const aware, but it doesn't modify the buffer + BIO *bio = BIO_new_mem_buf(const_cast<char*>(input.c_str()), input.length()); + bio = BIO_push(b64, bio); + size_t bytes_written = BIO_read(bio, buffer, buffer_size); + BIO_free_all(bio); - return len; + return bytes_written; } std::string LLBase64::decode(const std::string& input) @@ -91,8 +91,16 @@ std::string LLBase64::decode(const std::string& input) } // static -U32 LLBase64::requiredDecryptionSpace(const std::string& str) +size_t LLBase64::requiredDecryptionSpace(const std::string& str) { - return apr_base64_decode_len(str.c_str()); + size_t len = str.length(); + U32 padding = 0; + + if (str[len - 1] == '=' && str[len - 2] == '=') //last two chars are = + padding = 2; + else if (str[len - 1] == '=') //last char is = + padding = 1; + + return len * 0.75 - padding; } diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h index 302dde5506a4cf3861d8f386faca4476ed6c43d6..064da10a1f4d348fdd1873e383eaa4f9e45ee53f 100755 --- a/indra/llcommon/llbase64.h +++ b/indra/llcommon/llbase64.h @@ -35,7 +35,7 @@ public: static std::string encode(const U8* input, size_t input_size); static size_t decode(const std::string& input, U8 * buffer, size_t buffer_size); static std::string decode(const std::string& input); - static U32 requiredDecryptionSpace(const std::string& str); + static size_t requiredDecryptionSpace(const std::string& str); }; #endif diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 4f84ce974aafa9c46cd35b33183e5608460f792b..4daee3928cb6e23004f895779a0c0b8d1de5d593 100755 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -30,9 +30,9 @@ #include "llsdserialize.h" #include "llpointer.h" #include "llstreamtools.h" // for fullread +#include "llbase64.h" #include <iostream> -#include "apr_base64.h" #ifdef LL_USESYSTEMLIBS # include <zlib.h> @@ -807,12 +807,12 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const get(istr, *(coded_stream.rdbuf()), '\"'); c = get(istr); std::string encoded(coded_stream.str()); - S32 len = apr_base64_decode_len(encoded.c_str()); + size_t len = LLBase64::requiredDecryptionSpace(encoded); std::vector<U8> value; if(len) { value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); + len = LLBase64::decode(encoded, &value[0], len); value.resize(len); } data = value; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 98646facb82d54b597a8c555565658efcbf73731..275a5ed7308d05298c9b3870d9fc16a5ca87c389 100755 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -26,11 +26,11 @@ #include "linden_common.h" #include "llsdserialize_xml.h" +#include "llbase64.h" #include <iostream> #include <deque> -#include "apr_base64.h" #include <boost/regex.hpp> extern "C" @@ -189,17 +189,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti } else { - // *FIX: memory inefficient. - // *TODO: convert to use LLBase64 ostr << pre << "<binary encoding=\"base64\">"; - int b64_buffer_length = apr_base64_encode_len(buffer.size()); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - buffer.size()); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; + ostr << LLBase64::encode(&buffer[0], buffer.size()); ostr << "</binary>" << post; } break; @@ -780,10 +771,10 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) boost::regex r; r.assign("\\s"); std::string stripped = boost::regex_replace(mCurrentContent, r, ""); - S32 len = apr_base64_decode_len(stripped.c_str()); + size_t len = LLBase64::requiredDecryptionSpace(stripped); std::vector<U8> data; data.resize(len); - len = apr_base64_decode_binary(&data[0], stripped.c_str()); + len = LLBase64::decode(stripped, &data[0], len); data.resize(len); value = data; break; diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index d3e195789bf84222a0dc63d5f2ea13233fa53765..ee331bf63db39d6f9035e8154ff70eeeb5c39100 100755 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -72,11 +72,11 @@ #include "linden_common.h" #include "llfiltersd2xmlrpc.h" +#include "llbase64.h" #include <sstream> #include <iterator> #include <xmlrpc-epi/xmlrpc.h> -#include "apr_base64.h" #include "llbuffer.h" #include "llbufferstream.h" @@ -267,15 +267,7 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) LLSD::Binary buffer = sd.asBinary(); if(!buffer.empty()) { - // *TODO: convert to LLBase64 - int b64_buffer_length = apr_base64_encode_len(buffer.size()); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - buffer.size()); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; + ostr << LLBase64::encode(&buffer[0], buffer.size()); } ostr << "</base64>"; break; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e178546675393736799f1b61ecedeede2ab7e79c..e7ca2d940b0baccebe4d62596d0dfdfb76d42e22 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -66,9 +66,6 @@ #include "stringize.h" -// for base64 decoding -#include "apr_base64.h" - #define USE_SESSION_GROUPS 0 extern LLMenuBarGL* gMenuBarView; @@ -4480,8 +4477,8 @@ bool LLVivoxVoiceClient::IDFromName(const std::string inName, LLUUID &uuid) LLStringUtil::replaceChar(temp, '-', '+'); LLStringUtil::replaceChar(temp, '_', '/'); - U8 rawuuid[UUID_BYTES + 1]; - int len = apr_base64_decode_binary(rawuuid, temp.c_str() + 1); + U8 rawuuid[UUID_BYTES + 1]; + int len = LLBase64::decode(temp, rawuuid, UUID_BYTES + 1); if(len == UUID_BYTES) { // The decode succeeded. Stuff the bits into the result's UUID diff --git a/indra/newview/tests/llsechandler_basic_test.cpp b/indra/newview/tests/llsechandler_basic_test.cpp index 2a8dc153466a7ee12efe56f815d7f027c9774855..3aa2e8c7bcbb3c76fbf592b5425f31655be2d03b 100755 --- a/indra/newview/tests/llsechandler_basic_test.cpp +++ b/indra/newview/tests/llsechandler_basic_test.cpp @@ -31,9 +31,9 @@ #include "../llsechandler_basic.h" #include "../../llxml/llcontrol.h" #include "../llviewernetwork.h" +#include "llbase64.h" #include "lluuid.h" #include "llxorcipher.h" -#include "apr_base64.h" #include <vector> #include <ios> #include <llsdserialize.h> @@ -331,7 +331,8 @@ namespace tut mPemTestCert, test_cert->getPem()); std::vector<U8> binary_cert = test_cert->getBinary(); - apr_base64_encode(buffer, (const char *)&binary_cert[0], binary_cert.size()); + const std::string& tmp = LLBase64::encode(&binary_cert[0], binary_cert.size()); + std::strcpy(buffer, tmp.c_str()); ensure_equals("Der Format is correct", memcmp(buffer, mDerFormat.c_str(), mDerFormat.length()), 0); @@ -391,8 +392,8 @@ namespace tut "4ZT9Y4wZ9Rh8nnF3fDUL6IGamHe1ClXM1jgBu10F6UMhZbnH4C3aJ2E9+LiOntU+l3iCb2MpkEpr" "82r2ZAMwIrpnirL/xoYoyz7MJQYwUuMvBPToZJrxNSsjI+S2Z+I3iEJAELMAAA=="; - std::vector<U8> binary_data(apr_base64_decode_len(protected_data.c_str())); - apr_base64_decode_binary(&binary_data[0], protected_data.c_str()); + std::vector<U8> binary_data(LLBase64::requiredDecryptionSpace(protected_data)); + LLBase64::decode(protected_data, &binary_data[0], binary_data.size()); LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES); cipher.decrypt(&binary_data[0], 16); @@ -576,9 +577,9 @@ namespace tut // test loading of an unknown credential with legacy saved password and username std::string hashed_password = "fSQcLG03eyIWJmkzfyYaKm81dSweLmsxeSAYKGE7fSQ="; - int length = apr_base64_decode_len(hashed_password.c_str()); - std::vector<char> decoded_password(length); - apr_base64_decode(&decoded_password[0], hashed_password.c_str()); + size_t length = LLBase64::requiredDecryptionSpace(hashed_password); + std::vector<U8> decoded_password(length); + LLBase64::decode(hashed_password, &decoded_password[0], length); LLXORCipher cipher(gMACAddress, MAC_ADDRESS_BYTES); cipher.decrypt((U8*)&decoded_password[0], length); unsigned char unique_id[MAC_ADDRESS_BYTES]; @@ -586,7 +587,7 @@ namespace tut LLXORCipher cipher2(unique_id, sizeof(unique_id)); cipher2.encrypt((U8*)&decoded_password[0], length); llofstream password_file("test_password.dat", std::ofstream::binary); - password_file.write(&decoded_password[0], length); + password_file.write(reinterpret_cast<char*>(&decoded_password[0]), length); password_file.close(); my_new_cred = handler->loadCredential("my_legacy_grid2");