// // The developer of the original code and/or files is Tripwire, Inc. // Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire, // Inc. Tripwire is a registered trademark of Tripwire, Inc. All rights // reserved. // // This program is free software. The contents of this file are subject // to the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. You may redistribute it and/or modify it // only in compliance with the GNU General Public License. // // This program is distributed in the hope that it will be useful. // However, this program is distributed AS-IS WITHOUT ANY // WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS // FOR A PARTICULAR PURPOSE. Please see the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // // Nothing in the GNU General Public License or any other license to use // the code or files shall permit you to use Tripwire's trademarks, // service marks, or other intellectual property without Tripwire's // prior written consent. // // If you have any questions, please contact Tripwire, Inc. at either // info@tripwire.org or www.tripwire.org. // /////////////////////////////////////////////////////////////////////////////// // twutil.cpp // #include "stdtw.h" #include "twutil.h" #include "twcrypto/crypto.h" #include "core/archive.h" #include "core/serializerimpl.h" #include "twcrypto/cryptoarchive.h" #include "fcoreport.h" #include "twcrypto/keyfile.h" #include "fco/fcospeclist.h" #include "fco/genreswitcher.h" #include "core/errorbucketimpl.h" #include "core/cmdlineparser.h" #include "configfile.h" #include "core/fileheader.h" #include "core/usernotify.h" #include "policyfile.h" #include "core/serstring.h" #include "headerinfo.h" #include "systeminfo.h" #include "core/errorgeneral.h" #include "fco/parsergenreutil.h" #include "fco/twfactory.h" #include "fco/fconame.h" #include "fcodatabasefile.h" #include "util/fileutil.h" #include "core/stringutil.h" #include "tw/twstrings.h" #include "tw/twerrors.h" #include "core/ntmbs.h" #include "core/displayencoder.h" #ifdef TW_PROFILE #include "core/tasktimer.h" #endif #include "core/fsservices.h" // for the util_IsDir() stuff #if IS_UNIX #include #include #include #include #include "core/tw_signal.h" int _getch(void); #endif #ifdef _UNICODE // right now we only need this for unicode #include #endif // constants static const char* POLICY_FILE_MAGIC_8BYTE = "#POLTXT\n"; static const char* CONFIG_FILE_MAGIC_8BYTE = "#CFGTXT\n"; static const uint32 CURRENT_FIXED_VERSION = 0x02020000; /////////////////////////////////////////////////////////////////////////////// // WriteObjectToArchive -- called from WriteObject, does most of the work /////////////////////////////////////////////////////////////////////////////// static void WriteObjectToArchive(cArchive &arch, const TCHAR* filename, // filename is used only for issuing error messages const iTypedSerializable* pObjHeader, const iTypedSerializable& obj, cFileHeader& fileHeader, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { try { // Set file version. // If we in the future we wish to support reading databases of different versions, // we will have to move this set to outside WriteObject(). fileHeader.SetVersion(CURRENT_FIXED_VERSION); fileHeader.SetEncoding(bEncrypt ? cFileHeader::ASYM_ENCRYPTION : cFileHeader::COMPRESSED); { cSerializerImpl fhSer(arch, cSerializerImpl::S_WRITE, filename); fileHeader.Write(&fhSer); } if (bEncrypt) { cElGamalSigArchive cryptoArchive; cryptoArchive.SetWrite(&arch, pPrivateKey); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_WRITE, filename); ser.Init(); if(pObjHeader) ser.WriteObject(pObjHeader); ser.WriteObject(&obj); ser.Finit(); cryptoArchive.FlushWrite(); } else { // not encrypted cNullCryptoArchive cryptoArchive; cryptoArchive.Start(&arch); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_WRITE, filename); ser.Init(); if(pObjHeader) ser.WriteObject(pObjHeader); ser.WriteObject(&obj); ser.Finit(); cryptoArchive.Finish(); } } catch (eError& e) { throw ePoly( e.GetID(), cErrorUtil::MakeFileError( e.GetMsg(), filename ), e.GetFlags() ); } } /////////////////////////////////////////////////////////////////////////////// // WriteObject -- template class that writes an object to disk (ie -- report, // db, etc) either encrypted or unencrypted. // The only requrement on the object is that it is typed serializable. // errorMsg is a number that can be passed to iUserString to indicate an // appropriate error message if the object fails to load // // 10/30 -- this function has been expanded to take two objects -- a header and // an object. Both are typed serializable, but the header can be NULL if // none is desired. /////////////////////////////////////////////////////////////////////////////// static void WriteObject(const TCHAR* filename, const iTypedSerializable* pObjHeader, const iTypedSerializable& obj, cFileHeader& fileHeader, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cDebug d("WriteObject"); d.TraceDebug(_T("Writing %s to file %s\n"), obj.GetType().AsString(), filename); ASSERT(pPrivateKey || (! bEncrypt)); cFileArchive arch; if (!cFileUtil::IsRegularFile(filename) && cFileUtil::FileExists(filename)) throw eArchiveNotRegularFile( filename ); try { arch.OpenReadWrite( filename ); } catch (eArchive&) { // probably better to rethrow this as a write failed exception throw eArchiveWrite( filename, iFSServices::GetInstance()->GetErrString() ) ; } WriteObjectToArchive(arch, filename, pObjHeader, obj, fileHeader, bEncrypt, pPrivateKey); arch.Close(); } /////////////////////////////////////////////////////////////////////////////// // WriteObjectToArchive -- called from WriteObject, does most of the work /////////////////////////////////////////////////////////////////////////////// static void ReadObjectFromArchive(cArchive &arch, const TCHAR* objFileName, iTypedSerializable* pObjHeader, iTypedSerializable& obj, const cFileHeaderID& fhid, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted) { cFileHeader fileHeader; { cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, objFileName); fileHeader.Read(&fhSer); } // check for a mismatched header if (fileHeader.GetID() != fhid) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE)); // Check file version. // If we in the future we wish to support reading objects of different versions, // we will have to move this check to outside ReadObject(). if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION) ThrowAndAssert(eSerializerVersionMismatch(_T(""), objFileName, eSerializer::TY_FILE)); try { // switch on the type of encoding... if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION) { // tell the user the db is encrypted iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString( cTW, tw::STR_FILE_ENCRYPTED).c_str()); bEncrypted = true; if (pPublicKey == 0) ThrowAndAssert(eSerializerEncryption(_T(""))); cElGamalSigArchive cryptoArchive; cryptoArchive.SetRead(&arch, pPublicKey); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ, objFileName); ser.Init(); if(pObjHeader) ser.ReadObject(pObjHeader); ser.ReadObject(&obj); ser.Finit(); } else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED) { //not encrypted db... bEncrypted = false; cNullCryptoArchive cryptoArchive; cryptoArchive.Start(&arch); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ, objFileName); ser.Init(); if(pObjHeader) ser.ReadObject(pObjHeader); ser.ReadObject(&obj); ser.Finit(); } else // unknown encoding... ThrowAndAssert(eSerializerInputStreamFmt(_T(""))); } catch (eError& e) { // include filename in error msg throw ePoly( e.GetID(), cErrorUtil::MakeFileError( e.GetMsg(), objFileName ), e.GetFlags() ); } } /////////////////////////////////////////////////////////////////////////////// // ReadObject -- writes an object from disk, either encrypted or not, that was // written using WriteObject above. /////////////////////////////////////////////////////////////////////////////// static void ReadObject(const TCHAR* objFileName, iTypedSerializable* pObjHeader, iTypedSerializable& obj, const cFileHeaderID& fhid, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted) { cDebug d("ReadObject"); d.TraceDebug(_T("Reading %s from file %s\n"), obj.GetType().AsString(), objFileName); cFileArchive arch; arch.OpenRead( objFileName ); ReadObjectFromArchive(arch, objFileName, pObjHeader, obj, fhid, pPublicKey, bEncrypted); } /////////////////////////////////////////////////////////////////////////////// // IsObjectEncrypted /////////////////////////////////////////////////////////////////////////////// bool cTWUtil::IsObjectEncrypted( const TCHAR* objFileName, const cFileHeaderID& fhid, const TSTRING& errorMsg ) { bool fEncrypted = false; cDebug d("IsObjectEncrypted"); d.TraceDebug(_T("Reading from file %s\n"), objFileName); try { cFileArchive arch; arch.OpenRead( objFileName ); cFileHeader fileHeader; cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, objFileName); fileHeader.Read(&fhSer); // check for a mismatched header if (fileHeader.GetID() != fhid) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE)); // switch on the type of encoding... if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION) { fEncrypted = true; } else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED) { fEncrypted = false; } else // unknown encoding... ThrowAndAssert(eSerializerInputStreamFmt(_T(""), objFileName, eSerializer::TY_FILE)); } catch(eArchive& e) { // Note: Output to TCERR is O.K. here, it is documented that this is what this function does TSTRING msg = e.GetMsg(); if( ! msg.empty() ) msg += _T("\n"); msg += errorMsg; cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() )); ThrowAndAssert(ePoly()); } catch(eSerializer& e) { // Note: Output to TCERR is O.K. here, it is documented that this is what this function does TSTRING msg = e.GetMsg(); if( ! msg.empty() ) msg += _T("\n"); msg += errorMsg; cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() )); ThrowAndAssert(ePoly()); } return( fEncrypted ); } bool cTWUtil::IsObjectEncrypted( cArchive &arch, const cFileHeaderID& fhid, const TSTRING& errorMsg ) { bool fEncrypted = false; cDebug d("IsObjectEncrypted"); d.TraceDebug(_T("Reading from archive\n")); try { cFileHeader fileHeader; cSerializerImpl fhSer(arch, cSerializerImpl::S_READ, TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str()); fileHeader.Read(&fhSer); // check for a mismatched header if (fileHeader.GetID() != fhid) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str(), eSerializer::TY_FILE)); // switch on the type of encoding... if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION) { fEncrypted = true; } else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED) { fEncrypted = false; } else // unknown encoding... ThrowAndAssert(eSerializerInputStreamFmt(_T(""), TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME).c_str(), eSerializer::TY_FILE)); } catch(eArchive& e) { // Note: Output to TCERR is O.K. here, it is documented that this is what this function does TSTRING msg = e.GetMsg(); if( ! msg.empty() ) msg += _T("\n"); msg += errorMsg; cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() )); ThrowAndAssert(ePoly()); } catch(eSerializer& e) { // Note: Output to TCERR is O.K. here, it is documented that this is what this function does TSTRING msg = e.GetMsg(); if( ! msg.empty() ) msg += _T("\n"); msg += errorMsg; cTWUtil::PrintErrorMsg(ePoly(e.GetID(), msg, e.GetFlags() )); ThrowAndAssert(ePoly()); } return( fEncrypted ); } /////////////////////////////////////////////////////////////////////////////// // WriteDatabase /////////////////////////////////////////////////////////////////////////////// void cTWUtil::WriteDatabase(const TCHAR* filename, cFCODatabaseFile& db, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cFileHeader fileHeader; fileHeader.SetID(db.GetFileHeaderID()); // I am almost positive that this does nothing, WriteObject() sets the version in the cFileHeader - Jun 8, 1999 - dmb //fileHeader.SetVersion(1); #ifdef TW_PROFILE cWin32TaskTimer timer(_T("Write Database")); timer.Start(); #endif WriteObject(filename, 0, db, fileHeader, bEncrypt, pPrivateKey); #ifdef TW_PROFILE timer.Stop(); #endif iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_DB_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); } /////////////////////////////////////////////////////////////////////////////// // ReadDatabase /////////////////////////////////////////////////////////////////////////////// void cTWUtil::ReadDatabase(const TCHAR* filename, cFCODatabaseFile& db, const cElGamalSigPublicKey* pPublicKey, bool& bEncrypted) { iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_DB_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); #ifdef TW_PROFILE cWin32TaskTimer timer("cTWUtil::ReadDatabase"); timer.Start(); #endif ReadObject(filename, 0, db, cFCODatabaseFile::GetFileHeaderID(), pPublicKey, bEncrypted); #ifdef TW_PROFILE timer.Stop(); #endif } /////////////////////////////////////////////////////////////////////////////// // WriteReport /////////////////////////////////////////////////////////////////////////////// void cTWUtil::WriteReport(const TCHAR* filename, const cFCOReportHeader& reportHeader, const cFCOReport& r, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cFileHeader fileHeader; fileHeader.SetID(cFCOReport::GetFileHeaderID()); WriteObject(filename, &reportHeader, r, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_REPORT_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); } void cTWUtil::WriteReport(cArchive &archive, const cFCOReportHeader& reportHeader, const cFCOReport& r, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cFileHeader fileHeader; fileHeader.SetID(cFCOReport::GetFileHeaderID()); TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); WriteObjectToArchive(archive, filename.c_str(), &reportHeader, r, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_REPORT_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); } /////////////////////////////////////////////////////////////////////////////// // ReadReport /////////////////////////////////////////////////////////////////////////////// void cTWUtil::ReadReport(const TCHAR* reportFileName, cFCOReportHeader& reportHeader, cFCOReport& r, const cElGamalSigPublicKey* pPublicKey, bool silent, bool& bEncrypted) { iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_REPORT_FILE).c_str(), cDisplayEncoder::EncodeInline( reportFileName ).c_str() ); ReadObject(reportFileName, &reportHeader, r, cFCOReport::GetFileHeaderID(), pPublicKey, bEncrypted); } void cTWUtil::ReadReport(cArchive &archive, cFCOReportHeader& reportHeader, cFCOReport& r, const cElGamalSigPublicKey* pPublicKey, bool silent, bool& bEncrypted) { TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_REPORT_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str()); ReadObjectFromArchive(archive, filename.c_str(), &reportHeader, r, cFCOReport::GetFileHeaderID(), pPublicKey, bEncrypted); } /////////////////////////////////////////////////////////////////////////////// // UpdatePolicyFile /////////////////////////////////////////////////////////////////////////////// void cTWUtil::UpdatePolicyFile(const TCHAR* destFileName, const TCHAR* srcFileName, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cFileArchive src; src.OpenRead(srcFileName); // note: eArchive may float up std::string policyText; policyText.resize(src.Length()); src.ReadBlob((void*)policyText.data(), src.Length()); // NOTE -- this method will emit a message to stdout when the file has been written cTWUtil::WritePolicyText(destFileName, policyText, bEncrypt, pPrivateKey); } TSTRING cTWUtil::GetCfgFilePath(const cCmdLineParser& cmdLine, int cfgFileID) { TSTRING cfgFilePath; bool fConfigOnCmdLine = false; // let's see if this was specified on the command line... cCmdLineIter iter(cmdLine); for(iter.SeekBegin(); ! iter.Done(); iter.Next()) { if(iter.ArgId() == cfgFileID) { ASSERT(iter.NumParams() > 0); cfgFilePath = iter.ParamAt(0); fConfigOnCmdLine = true; } } // OK, now we need to figure out where to find the config file. // If the location was specified on the command line, get the full path to it. // otherwise, the location is the dir that this exe is in. if( fConfigOnCmdLine ) { TSTRING pathOut; iFSServices::GetInstance()->FullPath( pathOut, cfgFilePath ) ; cfgFilePath = pathOut; } else { iFSServices::GetInstance()->FullPath( cfgFilePath, TSS_GetString(cTW, tw::STR_DEF_CFG_FILENAME), cSystemInfo::GetExeDir() ) ; } cFileUtil::TestFileExists(cfgFilePath); return (cfgFilePath); } /////////////////////////////////////////////////////////////////////////////// // OpenConfigFile -- opens the config file, either from a known location or // from the location specified on the command line. Returns false if it fails. // cfgFileID is the ID of the config file switch // TODO -- should this guy spit the error to cerr or fill up an error bucket? ///////////////////////////////////////////////////////////////////////////////// void cTWUtil::OpenConfigFile(cConfigFile& cf, cCmdLineParser& cmdLine, int cfgFileID, cErrorBucket& errorBucket, TSTRING& configFileOut) { configFileOut = GetCfgFilePath(cmdLine, cfgFileID); // ok, now let's load it! TSTRING configText; cTWUtil::ReadConfigText(configFileOut.c_str(), configText); cf.ReadString( configText ); } /////////////////////////////////////////////////////////////////////////////// // WriteConfigText // eArchive is thrown if filename can not be opened // eSerializer is thrown if reading or writing fails void cTWUtil::WriteConfigText(const TCHAR* filename, const TSTRING configText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cSerializableNString nstring; nstring.mString = CONFIG_FILE_MAGIC_8BYTE; std::string ns; cStringUtil::Convert( ns, configText ); nstring.mString += ns; cFileHeader fileHeader; fileHeader.SetID(cConfigFile::GetFileHeaderID()); fileHeader.SetVersion(CURRENT_FIXED_VERSION); if (bEncrypt) { ASSERT(pPrivateKey != 0); cElGamalSigPublicKey publicKey(*pPrivateKey); fileHeader.GetBaggage().MapArchive(0, publicKey.GetWriteLen()); publicKey.Write(fileHeader.GetBaggage().GetMap()); } WriteObject(filename, NULL, nstring, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_CONFIG_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); } void cTWUtil::WriteConfigText(cArchive &archive, const TSTRING configText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cSerializableNString nstring; nstring.mString = CONFIG_FILE_MAGIC_8BYTE; TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); std::string ns; cStringUtil::Convert( ns, configText ); nstring.mString += ns; cFileHeader fileHeader; fileHeader.SetID(cConfigFile::GetFileHeaderID()); fileHeader.SetVersion(CURRENT_FIXED_VERSION); if (bEncrypt) { ASSERT(pPrivateKey != 0); cElGamalSigPublicKey publicKey(*pPrivateKey); fileHeader.GetBaggage().MapArchive(0, publicKey.GetWriteLen()); publicKey.Write(fileHeader.GetBaggage().GetMap()); } WriteObjectToArchive(archive, filename.c_str(), NULL, nstring, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_CONFIG_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str()); } /////////////////////////////////////////////////////////////////////////////// // ReadConfigText // eArchive is thrown if filename can not be opened // eSerializer is thrown if reading or writing fails // eConfigFile is thrown if config file does not parse correctly during reading void cTWUtil::ReadConfigText(const TCHAR* filename, TSTRING& configText, cArchive* pBaggage) { // TODO -- neat up this function; try to use LoadObject() above... cSerializableNString nstring; // This was coppied from ReadObject(). We need to use the baggage of the // file header to obtain the public key, thus the special casing. cDebug d("ReadConfigText"); d.TraceDebug(_T("Reading %s from file %s\n"), nstring.GetType().AsString(), filename); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_CONFIG_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); cFileArchive arch; arch.OpenRead( filename ); cFileHeader fileHeader; try { cSerializerImpl fhSer(arch, cSerializerImpl::S_READ); fileHeader.Read(&fhSer); } catch (eError&) { throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE); } #if 0 // XXX: This is broken, what the h*ll are they trying to write here? -PH d.TraceDebug("Found a file header of type %d.\n", fileHeader.GetEncoding()); #endif // check for a mismatched header if (fileHeader.GetID() != cConfigFile::GetFileHeaderID()) throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE); // check the version if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION) throw eSerializerVersionMismatch(_T(""), filename, eSerializer::TY_FILE); // switch on the type of encoding... if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION) { d.TraceDebug("Config file is compressed, public key len %d.\n", fileHeader.GetBaggage().Length()); // tell the user the db is encrypted iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_FILE_ENCRYPTED).c_str()); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_NEWLINE).c_str()); ASSERT(fileHeader.GetBaggage().Length() > 0); if (fileHeader.GetBaggage().Length() <= 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE)); fileHeader.GetBaggage().MapArchive(0, fileHeader.GetBaggage().Length()); cElGamalSigPublicKey publicKey(fileHeader.GetBaggage().GetMap()); cElGamalSigArchive cryptoArchive; cryptoArchive.SetRead(&arch, &publicKey); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ); ser.Init(); ser.ReadObject(&nstring); ser.Finit(); // copy the baggage into the archive, if it was passed in // Note: We rely in VerifySiteKey that we only fill out pBaggage if // the config file is encrypted. // if( pBaggage ) { fileHeader.GetBaggage().Seek( 0, cBidirArchive::BEGINNING ); pBaggage->Copy( &fileHeader.GetBaggage(), fileHeader.GetBaggage().Length() ); } } else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED) { d.TraceDebug("Config file is not compressed.\n"); //not encrypted db... cNullCryptoArchive cryptoArchive; cryptoArchive.Start(&arch); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ); ser.Init(); ser.ReadObject(&nstring); ser.Finit(); } else // unknown encoding... throw eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE); // check 8 byte header if (nstring.mString.compare(0, 8*sizeof(byte), CONFIG_FILE_MAGIC_8BYTE) != 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE)); // remove 8 byte header nstring.mString.assign(nstring.mString.substr(8)); cStringUtil::Convert( configText, nstring.mString ); } void cTWUtil::ReadConfigText(cArchive &arch, TSTRING& configText, cArchive* pBaggage) { // TODO -- neat up this function; try to use LoadObject() above... cSerializableNString nstring; TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); // This was coppied from ReadObject(). We need to use the baggage of the // file header to obtain the public key, thus the special casing. cDebug d("ReadConfigText"); d.TraceDebug(_T("Reading %s from file %s\n"), nstring.GetType().AsString(), filename.c_str()); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_CONFIG_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str()); cFileHeader fileHeader; try { cSerializerImpl fhSer(arch, cSerializerImpl::S_READ); fileHeader.Read(&fhSer); } catch (eError&) { throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE); } #if 0 // XXX: This is broken, how can you convert a class to an int??? -PH d.TraceDebug("Found a file header of type %d.\n", fileHeader.GetEncoding()); #endif // check for a mismatched header if (fileHeader.GetID() != cConfigFile::GetFileHeaderID()) throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE); // check the version if (fileHeader.GetVersion() != CURRENT_FIXED_VERSION) throw eSerializerVersionMismatch(_T(""), filename.c_str(), eSerializer::TY_FILE); // switch on the type of encoding... if(fileHeader.GetEncoding() == cFileHeader::ASYM_ENCRYPTION) { d.TraceDebug("Config file is compressed, public key len %d.\n", fileHeader.GetBaggage().Length()); // tell the user the db is encrypted iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_FILE_ENCRYPTED).c_str()); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, TSS_GetString(cTW, tw::STR_NEWLINE).c_str()); ASSERT(fileHeader.GetBaggage().Length() > 0); if (fileHeader.GetBaggage().Length() <= 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE)); fileHeader.GetBaggage().MapArchive(0, fileHeader.GetBaggage().Length()); cElGamalSigPublicKey publicKey(fileHeader.GetBaggage().GetMap()); cElGamalSigArchive cryptoArchive; cryptoArchive.SetRead(&arch, &publicKey); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ); ser.Init(); ser.ReadObject(&nstring); ser.Finit(); // copy the baggage into the archive, if it was passed in // Note: We rely in VerifySiteKey that we only fill out pBaggage if // the config file is encrypted. // if( pBaggage ) { fileHeader.GetBaggage().Seek( 0, cBidirArchive::BEGINNING ); pBaggage->Copy( &fileHeader.GetBaggage(), fileHeader.GetBaggage().Length() ); } } else if(fileHeader.GetEncoding() == cFileHeader::COMPRESSED) { d.TraceDebug("Config file is not compressed.\n"); //not encrypted db... cNullCryptoArchive cryptoArchive; cryptoArchive.Start(&arch); cSerializerImpl ser(cryptoArchive, cSerializerImpl::S_READ); ser.Init(); ser.ReadObject(&nstring); ser.Finit(); } else // unknown encoding... throw eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE); // check 8 byte header if (nstring.mString.compare(0, 8*sizeof(byte), CONFIG_FILE_MAGIC_8BYTE) != 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE)); // remove 8 byte header nstring.mString.assign(nstring.mString.substr(8)); cStringUtil::Convert( configText, nstring.mString ); } /////////////////////////////////////////////////////////////////////////////// // Given a filename and the text of a policy file, write an encrypted version // of the policy file text to disk. // Will throw eError on failure. void cTWUtil::WritePolicyText(const TCHAR* filename, const std::string polText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cSerializableNString nstring; // add a 8 byte header we can use to verify decryption nstring.mString = POLICY_FILE_MAGIC_8BYTE; nstring.mString += polText; cFileHeader fileHeader; fileHeader.SetID(cPolicyFile::GetFileHeaderID()); WriteObject(filename, NULL, nstring, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_POLICY_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str() ); } void cTWUtil::WritePolicyText(cArchive &archive, const std::string polText, bool bEncrypt, const cElGamalSigPrivateKey* pPrivateKey) { cSerializableNString nstring; TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); // add a 8 byte header we can use to verify decryption nstring.mString = POLICY_FILE_MAGIC_8BYTE; nstring.mString += polText; cFileHeader fileHeader; fileHeader.SetID(cPolicyFile::GetFileHeaderID()); WriteObjectToArchive(archive, filename.c_str(), NULL, nstring, fileHeader, bEncrypt, pPrivateKey); iUserNotify::GetInstance()->Notify( iUserNotify::V_NORMAL, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_WRITE_POLICY_FILE).c_str(), cDisplayEncoder::EncodeInline( filename ).c_str()); } /////////////////////////////////////////////////////////////////////////////// // ReadPolicyText // // Read the policy file. Read the text of a policy language into configText // Will throw eError on failure. /////////////////////////////////////////////////////////////////////////////// void cTWUtil::ReadPolicyText(const TCHAR* filename, std::string& polText, const cElGamalSigPublicKey* pPublicKey) { cSerializableNString nstring; cFileUtil::TestFileExists(filename); bool bEncrypted; ReadObject(filename, NULL, nstring, cPolicyFile::GetFileHeaderID(), pPublicKey, bEncrypted); // check 8 byte header if (nstring.mString.compare(0, 8*sizeof(byte), POLICY_FILE_MAGIC_8BYTE) != 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename, eSerializer::TY_FILE)); // remove 8 byte header nstring.mString.assign(nstring.mString.substr(8)); polText = nstring.mString; } void cTWUtil::ReadPolicyText(cArchive &archive, std::string& polText, const cElGamalSigPublicKey* pPublicKey) { cSerializableNString nstring; TSTRING filename = TSS_GetString( cTW, tw::STR_MEMORY_MAPPED_FILENAME); bool bEncrypted; ReadObjectFromArchive(archive, filename.c_str(), NULL, nstring, cPolicyFile::GetFileHeaderID(), pPublicKey, bEncrypted); // check 8 byte header if (nstring.mString.compare(0, 8*sizeof(byte), POLICY_FILE_MAGIC_8BYTE) != 0) ThrowAndAssert(eSerializerInputStreamFmt(_T(""), filename.c_str(), eSerializer::TY_FILE)); // remove 8 byte header nstring.mString.assign(nstring.mString.substr(8)); polText = nstring.mString; } /////////////////////////////////////////////////////////////////////////////// // OpenKeyFile /////////////////////////////////////////////////////////////////////////////// void cTWUtil::OpenKeyFile(cKeyFile& keyFile, TSTRING fileName) { // first, make sure the file exists... cFileUtil::TestFileExists(fileName); iUserNotify::GetInstance()->Notify( iUserNotify::V_VERBOSE, _T("%s%s\n"), TSS_GetString( cTW, tw::STR_OPEN_KEYFILE).c_str(), cDisplayEncoder::EncodeInline( fileName ).c_str()); keyFile.ReadFile(fileName.c_str()); } /////////////////////////////////////////////////////////////////////////////// // CreatePrivateKey // we will attempt to get the correct passphrase three times before we // give up. /////////////////////////////////////////////////////////////////////////////// const cElGamalSigPrivateKey* cTWUtil::CreatePrivateKey(cKeyFile& keyFile, const WCHAR16* usePassphrase, KeyType keyType, int nSecs) { ASSERT(keyType == KEY_SITE || keyType == KEY_LOCAL || keyType == KEY_PROVIDED); const cElGamalSigPrivateKey* pPrivateKey = NULL; wc16_string passphrase; if ( usePassphrase ) { // sleep to hinder brute force (dictionary, etc.) attacks iFSServices::GetInstance()->Sleep( nSecs ); passphrase = usePassphrase; #ifndef WORDS_BIGENDIAN passphrase.swapbytes(); #endif pPrivateKey = keyFile.GetPrivateKey((int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16)); if(pPrivateKey) return pPrivateKey; // if we got here, then a passphrase was provided on the command line that // was not correct; this is an error condition. // if( keyType == KEY_LOCAL ) throw eTWUtilBadPassLocal(); else throw eTWUtilBadPassSite(); } int count = 0; while(count < 3) { cTWUtil::NoEcho noEcho; switch (keyType) { case KEY_LOCAL: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_LOCAL_PASSPHRASE); break; case KEY_SITE: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_SITE_PASSPHRASE); break; case KEY_PROVIDED: default: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_PROVIDED_PASSPHRASE); break; } cTWUtil::GetString(passphrase); TCOUT << std::endl; // sleep to hinder brute force (dictionary, etc.) attacks iFSServices::GetInstance()->Sleep( nSecs ); #ifndef WORDS_BIGENDIAN passphrase.swapbytes(); #endif pPrivateKey = keyFile.GetPrivateKey((int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16)); if (pPrivateKey) break; // tell the user that they entered the wrong passphrase int strId = (keyType==KEY_LOCAL) ? tw::STR_ERR_WRONG_PASSPHRASE_LOCAL : tw::STR_ERR_WRONG_PASSPHRASE_SITE; TCOUT << TSS_GetString( cTW, strId) << std::endl; passphrase.resize(0); count++; } if(! pPrivateKey) throw ePoly(); return pPrivateKey; } void cTWUtil::CreatePrivateKey(cPrivateKeyProxy& proxy, cKeyFile& keyFile, const WCHAR16* usePassphrase, KeyType keyType, int nSecs) { ASSERT(keyType == KEY_SITE || keyType == KEY_LOCAL || keyType == KEY_PROVIDED); wc16_string passphrase; if (usePassphrase != 0) { // sleep to hinder brute force (dictionary, etc.) attacks iFSServices::GetInstance()->Sleep( nSecs ); passphrase = usePassphrase; #ifndef WORDS_BIGENDIAN passphrase.swapbytes(); #endif if (proxy.AquireKey(keyFile, (int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16))) return; // if we got here, then a passphrase was provided on the command line that // was not correct; this is an error condition. // if( keyType == KEY_LOCAL ) throw eTWUtilBadPassLocal(); else throw eTWUtilBadPassSite(); } int count = 0; while(count < 3) { cTWUtil::NoEcho noEcho; switch (keyType) { case KEY_LOCAL: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_LOCAL_PASSPHRASE); break; case KEY_SITE: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_SITE_PASSPHRASE); break; case KEY_PROVIDED: default: TCOUT << TSS_GetString( cTW, tw::STR_ENTER_PROVIDED_PASSPHRASE); break; } cTWUtil::GetString(passphrase); TCOUT << std::endl; // sleep to hinder brute force (dictionary, etc.) attacks iFSServices::GetInstance()->Sleep( nSecs ); #ifndef WORDS_BIGENDIAN passphrase.swapbytes(); #endif if (proxy.AquireKey(keyFile, (int8*)passphrase.data(), passphrase.length() * sizeof(WCHAR16))) return; // tell the user that they entered the wrong passphrase int strId = (keyType==KEY_LOCAL) ? tw::STR_ERR_WRONG_PASSPHRASE_LOCAL : (keyType==KEY_SITE) ? tw::STR_ERR_WRONG_PASSPHRASE_SITE : tw::STR_ERR_WRONG_PASSPHRASE_LOCAL; // TODO: make this provided TCOUT << TSS_GetString( cTW, strId) << std::endl; passphrase.resize(0); count++; } throw ePoly(); } /////////////////////////////////////////////////////////////////////////////// // GetStringNoEcho -- Get a string from the user without echoing it /////////////////////////////////////////////////////////////////////////////// #if IS_UNIX static void (*old_SIGINT)(int); static void (*old_SIGQUIT)(int); static struct termios Otty; static void RestoreEcho(int sig) { #ifdef _DEBUG std::cout << "Caught signal, resetting echo."<< std::endl; sleep(2); #endif tcsetattr( 0, TCSAFLUSH, &Otty); tw_signal(SIGINT, old_SIGINT); tw_signal(SIGQUIT, old_SIGQUIT); tw_raise(sig); } void cTWUtil::GetString(wc16_string& ret) { #ifdef _UNICODE #error We depend on Unix not being Unicode #endif // get the string const int MAX_STRING = 1024; char buf[MAX_STRING]; int len; TCOUT.flush(); len = read( 0, buf, MAX_STRING ); // TODO:BAM -- mb-enable this! if (len < MAX_STRING - 1) buf[len] = 0; char* psz = tss::strdec( buf, buf + len ); if ( *psz == '\n') *psz = 0; ret = cStringUtil::TstrToWstr( buf ); } cTWUtil::NoEcho::NoEcho() { // set the terminal to no echo mode static struct termios Ntty; fflush(stdout); tcgetattr( 0, &Otty); Ntty = Otty; Ntty.c_lflag &= ~ECHO; // catch SIGINT and SIGQUIT old_SIGINT = tw_signal(SIGINT, RestoreEcho); old_SIGQUIT = tw_signal(SIGQUIT, RestoreEcho); if (tcsetattr( 0, TCSAFLUSH, &Ntty) != 0 && isatty(0)) { ThrowAndAssert(eTWUtilEchoModeSet()); } } cTWUtil::NoEcho::~NoEcho() { tcsetattr( 0, TCSAFLUSH, &Otty); tw_signal(SIGINT, old_SIGINT); tw_signal(SIGQUIT, old_SIGQUIT); } void cTWUtil::GetStringNoEcho(wc16_string& ret) { NoEcho noEcho; GetString(ret); } #endif /////////////////////////////////////////////////////////////////////////////// // ParseObjectList /////////////////////////////////////////////////////////////////////////////// void cTWUtil::ParseObjectList( cTWUtil::GenreObjList& listOut, const cTWUtil::ObjList& listIn ) { cGenre::Genre curGenre = cGenreSwitcher::GetInstance()->GetDefaultGenre(); ASSERT( listIn.size() > 0 ); listOut.clear(); GenreObjList::iterator curIter = listOut.end(); cGenre::Genre iterGenre = cGenre::GENRE_INVALID; // iterate over all of the input... // for( ObjList::const_iterator i = listIn.begin(); i != listIn.end(); i++ ) { // first, try to interperate the current string as a genre name... // 17 Mar 99 mdb -- we now only do this if the string ends in a ':' // cGenre::Genre g = cGenre::GENRE_INVALID; if( i->at( i->length()-1 ) == _T(':') ) { TSTRING genreStr; genreStr.assign( i->begin(), i->end()-1 ); g = cGenreSwitcher::GetInstance()->StringToGenre( genreStr.c_str() ); // // if it is not a valid genre name, then test to see if it could // be an fconame. If it is not, then it is a badly formed genre. // if( g == cGenre::GENRE_INVALID ) { std::auto_ptr pParseUtil (iTWFactory::GetInstance()->CreateParserGenreUtil()); if( ! pParseUtil->IsAbsolutePath( *i ) ) throw eTWUnknownSectionName( *i ); } } if( g == cGenre::GENRE_INVALID ) { // assume that we are in the correct genre; this is a fully qualified object name // TODO -- throw here if cGenreParserHelper says it isn't a fully qualified name. // if( iterGenre != curGenre ) { // seek to right list; create it if it is not there... // for( curIter = listOut.begin(); curIter != listOut.end(); curIter++ ) { if( curIter->first == curGenre ) break; } if( curIter == listOut.end() ) { // it doesn't exist; we will have to create a new one. // listOut.push_back( GenreObjs() ); listOut.back().first = curGenre; curIter = listOut.end() - 1; } iterGenre = curGenre; } ASSERT( curIter != listOut.end() ); // // add this to the list; assert that it has not been added yet. // ObjList::iterator oi; for( oi = curIter->second.begin(); oi != curIter->second.end(); oi++ ) { if( *oi == *i ) { //TODO -- what should I do here? probably warn and continue... ASSERT( false ); break; } } if( oi == curIter->second.end() ) curIter->second.push_back( *i ); } else { // set the current genre to this and continue... // curGenre = g; } } } /////////////////////////////////////////////////////////////////////////////// // ParseObjectName /////////////////////////////////////////////////////////////////////////////// cFCOName cTWUtil::ParseObjectName( const TSTRING& fcoName ) { std::auto_ptr pParseUtil (iTWFactory::GetInstance()->CreateParserGenreUtil()); cFCOName name( iTWFactory::GetInstance()->GetNameInfo() ); // // make sure the fco name is a full path... // if( ! pParseUtil->IsAbsolutePath( fcoName ) ) throw eTWUtilNotFullPath( fcoName ); // // construct the list that InterpretFCOName needs.... std::list inputNameList; // // dice up the string into a list // currently, we only slice it up based on "|" (for nt registry entries) // TSTRING::size_type pos = fcoName.find_first_of( _T('|') ); if( pos != TSTRING::npos ) { // if the input string is "foo|bar" then we want the list to // look like this: "foo", "|", "bar" (three entries) // TSTRING str; str.assign( fcoName, 0, pos ); inputNameList.push_back( str ); inputNameList.push_back( _T("|") ); str.assign( fcoName, pos+1, fcoName.length() - pos ); inputNameList.push_back( str ); } else { inputNameList.push_back( fcoName ); } pParseUtil->InterpretFCOName( inputNameList, name ) ; return name; } /////////////////////////////////////////////////////////////////////////////// // Database and report header helpers /////////////////////////////////////////////////////////////////////////////// TSTRING cTWUtil::GetSystemName() { TSTRING ret; iFSServices::GetInstance()->GetMachineName(ret); return ret; } TSTRING cTWUtil::GetIPAddress() { uint32 ipaddress; if (iFSServices::GetInstance()->GetIPAddress(ipaddress) == false) return TSS_GetString( cTW, tw::STR_IP_UNKNOWN); // convert to host byte-order ipaddress = tw_ntohl( ipaddress ); TOSTRINGSTREAM ret; ret << (int)(ipaddress >> 24) << _T(".") << (int)((ipaddress >> 16) & 0xff) << _T(".") << (int)((ipaddress >> 8) & 0xff) << _T(".") << (int)(ipaddress & 0xff); return ret.str(); } TSTRING cTWUtil::GetCurrentUser() { TSTRING ret; iFSServices::GetInstance()->GetCurrentUserName(ret); return ret; } TSTRING cTWUtil::GetHostID() { TSTRING ret; iFSServices::GetInstance()->GetHostID(ret); return ret; } /////////////////////////////////////////////////////////////////////////////// // PrintErrorMsg /////////////////////////////////////////////////////////////////////////////// void cTWUtil::PrintErrorMsg(const eError& e, const TSTRING& strExtra) { ASSERT( e.GetID() != 0 ); // NOTE: BAM 5/9/99 -- there should no longer be an ID of ZERO /* BAM 5/9/99 -- this is old stuff if((e.GetID() == 0) && (e.GetMsg().empty())) { // this should only occur at the top level of a program (ie -- twcmdline.cpp) and // indicates that an error occurred and an error message has already been printed out. // Therefore, we will do nothing here but return. return; } */ cErrorReporter::PrintErrorMsg(e, strExtra); } /////////////////////////////////////////////////////////////////////////////// // ConfirmYN(const TCHAR* prompt) // // prompt the user with given string and wait for a 'Y' or 'N' response. // returns true if 'Y' entered. /////////////////////////////////////////////////////////////////////////////// bool cTWUtil::ConfirmYN(const TCHAR* prompt) { wc16_string reply; TSTRING s; int x; while (1) { TCOUT << prompt; GetString(reply); cStringUtil::Convert(s, reply); #ifdef UNICODE for (x = 0; s[x] && iswctype(s[x], wctype("space") ); x++) ; #else for (x = 0; s[x] && std::isspace( s[x], std::locale() ); x++) ; #endif if (_totupper(s[x]) == _T('Y')) return true; else if (_totupper(s[x]) == _T('N')) return false; } } /////////////////////////////////////////////////////////////////////////////// // VerifySiteKey /////////////////////////////////////////////////////////////////////////////// bool cTWUtil::VerifyCfgSiteKey( const TSTRING& strConfigFile, const TSTRING& siteKeyPath ) { // open the config file // cMemoryArchive memArch; try { TSTRING dummyString; cTWUtil::ReadConfigText( strConfigFile.c_str(), dummyString, &memArch ); } catch (eArchive& e) { // if the file is corrupted, eArchive may be thrown. // For sanity sake we need to re-throw this as eTWUtil TSTRING estr; estr.assign(TSS_GetString( cCore, core::STR_ERROR_FILENAME )); estr.append(strConfigFile); estr.append(TSS_GetString( cCore, core::STR_NEWLINE )); estr.append(e.GetMsg()); throw eTWUtilCorruptedFile( estr ); } // only do the test if there is baggage (indicating the cfg file is encrypted) // ASSERT(memArch.Length() >= 0); if (memArch.Length() <= 0) return false; // get site public key // cKeyFile siteKeyfile; cTWUtil::OpenKeyFile( siteKeyfile, siteKeyPath ); // create the two public keys... // memArch.Seek( 0, cBidirArchive::BEGINNING ); cElGamalSigPublicKey pubKey( memArch.GetMemory() ); // compare the two .... // if( ! pubKey.IsEqual( *siteKeyfile.GetPublicKey() ) ) { TSTRING estr; estr.assign(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH1 )); estr.append(strConfigFile); estr.append(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH2 )); estr.append(siteKeyPath); estr.append(TSS_GetString( cTW, tw::STR_ERR2_CFG_KEY_MISMATCH3 )); throw eTWUtilCfgKeyMismatch( estr ); } return true; }