diff -r 000000000000 -r bde4ae8d615e os/security/securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/security/securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,858 @@ +/* +* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include "encdec.h" +#include +#include +#include +#include "stringconv.h" +#include +#include "x509utils.h" + +RDecodeReadStream::RDecodeReadStream(CFileStore *aStore, RReadStream &aReadStream) + : iStore(aStore), iCertBaseName(), iReadStream(aReadStream), iHumanReadable(false), iToken(), + iPrefetchedTokenIsValid(false), iPrefetchedToken() +{ +} + +RDecodeReadStream::RDecodeReadStream(const std::string &aCertBaseName, RReadStream &aReadStream) + : iStore(0), iCertBaseName(aCertBaseName), iReadStream(aReadStream), iHumanReadable(true), iToken(), + iPrefetchedTokenIsValid(false), iPrefetchedToken() +{ +} + +void RDecodeReadStream::RawRead(void *aPtr, TUint32 aLength) +{ + iReadStream.ReadL((TUint8 *)aPtr, aLength); +} + +void RDecodeReadStream::CheckName(const std::string &aExpected) +{ + ReadNextToken(); + + if(iToken != aExpected) + { + dbg << Log::Indent() << "Expected token '" << aExpected <<"' but got token '" << iToken << "'" << Log::Endl(); + FatalError(); + } + +} + +TUint32 ReadUnsignedNumber(std::string &aStr, size_t aSize) +{ + TUint32 val; + std::istringstream ss(aStr); + + if((aStr.length() > 2) && + (aStr[0] == '0') && + ((aStr[1] == 'x') || (aStr[1] == 'X'))) + { + // Hex number starting with 0x + char ch; + ss >> ch >> ch; // Discard the 0x + ss >> std::hex >> val; + } + else + { + // Decimal number + ss >> val; + } + + // Now work out if we consumed the entire token without error + if(ss.fail()) + { + // Number decode failed + dbg << Log::Indent() << "Failed to decode '" << aStr << "' as a number" << Log::Endl(); + FatalError(); + } + + // Make sure we consumed all data + if(! ss.eof()) + { + // Trailing chars on numeric token + FatalError(); + } + + if(aSize != 4) + { + // Check range + // nb the following check would fail if aSize==4 because x>>32 == x if sizeof(x)==4 + if((val >> (8*aSize)) != 0) + { + // Higher order bits are set above the size of the variable we + // are returning into + FatalError(); + } + } +return val; +} + + +TUint32 RDecodeReadStream::ReadUnsignedNumber(size_t aSize) +{ +BULLSEYE_OFF + if((TUint32(aSize)>4)) + { + FatalError(); + } +BULLSEYE_RESTORE + + ReadNextToken(); + + return ::ReadUnsignedNumber(iToken, aSize); +} + +const std::string &RDecodeReadStream::Token() const +{ + return iToken; +} + +void RDecodeReadStream::ReadNextToken() +{ + if(iPrefetchedTokenIsValid) + { + // Copy prefetched token to current token + iToken = iPrefetchedToken; + iPrefetchedToken.clear(); + iPrefetchedTokenIsValid = false; + return; + } + + GetToken(iToken); +} + +const std::string &RDecodeReadStream::PeakToken() +{ + if(!iPrefetchedTokenIsValid) + { + GetToken(iPrefetchedToken); + iPrefetchedTokenIsValid = true; + } + + return iPrefetchedToken; +} + + + + + +bool RDecodeReadStream::HumanReadable() const +{ + return iHumanReadable; +} + + +void RDecodeReadStream::Close() +{ + iReadStream.Close(); +} + +void RDecodeReadStream::GetToken(std::string &aToken) +{ + aToken.clear(); + + TUint8 ch; + do + { + iReadStream >> ch; + if(ch == '#') + { + // Skip comment + ++ch; + while((ch != '\r') && (ch != '\n')) + { + iReadStream >> ch; + } + + } + } while((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')); + + if(ch == '"') + { + // Read a string + iReadStream >> ch; // read first char + while(ch != '"') + { + if(ch=='\\') + { + // \X causes X to always be saved (even if X is ") + iReadStream >> ch; + } + + aToken.push_back(ch); + iReadStream >> ch; + } + // At this point ch contains WS so it can be discarded. + return; + } + + // Read a non-string token + while((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) + { + aToken.push_back(ch); + iReadStream >> ch; + } + // At this point ch contains WS so it can be discarded. + return; +} + + + + + +REncodeWriteStream::REncodeWriteStream(CFileStore *aStore, RWriteStream &aWriteStream) + : iStore(aStore), + iCertBaseName(), // not used for STORE based streams + iWriteStream(&aWriteStream), + iLogStream(0), + iHumanReadable(false), iPemOut(false), iVerbose(false), iIndentLevel(0) +{ +} + +REncodeWriteStream::REncodeWriteStream(const std::string &aCertBaseName, RWriteStream &aWriteStream) + : iStore(0), iCertBaseName(aCertBaseName), iWriteStream(&aWriteStream), + iLogStream(0), + iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(0) +{ +} + +REncodeWriteStream::REncodeWriteStream(Log &aLog) + : iStore(0), iWriteStream(0), iLogStream(&aLog.Stream()), + iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(aLog.IndentLevel()) +{ +} + +void REncodeWriteStream::WriteBin(const void *aPtr, TUint32 aLength) +{ + if(iWriteStream) + { + iWriteStream->WriteL((TUint8 *)aPtr, aLength); + } + if(iLogStream) + { + iLogStream->write((const char *)aPtr, aLength); + iLogStream->flush(); + } +} + +void REncodeWriteStream::WriteQuotedUtf8(const void *aStr, TUint32 aLength) +{ + std::string tmp((const char *)aStr, aLength); + + // Insert a backslash before any backslash chars + size_t pos = 0; + while((pos = tmp.find('\\', pos)) != std::string::npos) + { + tmp.insert(pos, "\\", 1); + pos += 2; + } + + // Insert a backslash before any double quote chars + pos = 0; + while((pos = tmp.find('"', pos)) != std::string::npos) + { + tmp.insert(pos, "\\", 1); + pos += 2; + } + + if(iWriteStream) + { + iWriteStream->WriteL((TUint8 *)tmp.data(), tmp.size()); + } + if(iLogStream) + { + iLogStream->write(tmp.data(), tmp.size()); + iLogStream->flush(); + } +} + +void REncodeWriteStream::WriteByte(TUint8 aByte) +{ + WriteBin(&aByte, 1); +} + +void REncodeWriteStream::WriteCStr(const void *aCstr) +{ + WriteBin(aCstr, strlen((const char *)aCstr)); +} + +void REncodeWriteStream::WriteHexNumber(TUint32 aNumber) +{ + char buf[20]; + int len = sprintf(buf, "0x%x", aNumber); + WriteBin(buf, len); +} + + +void REncodeWriteStream::WriteSpace() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE + WriteByte(' '); +} + +void REncodeWriteStream::WriteLineEnd() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE +#ifdef linux + WriteByte('\n'); +#else + WriteBin("\r\n", 2); +#endif +} + + +void REncodeWriteStream::WriteIndent() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE + for(int i=0; iClose(); + } +} + +CFileStore *REncodeWriteStream::StoreObject() +{ +BULLSEYE_OFF + if(iStore == 0) FatalError(); +BULLSEYE_RESTORE + return iStore; +} + +RWriteStream &REncodeWriteStream::StoreWriteStream() +{ +BULLSEYE_OFF + if(iWriteStream == 0) FatalError(); +BULLSEYE_RESTORE + return *iWriteStream; +} + +bool REncodeWriteStream::Quiet() const +{ + return iLogStream != 0; +} + +TUint8 fromHex(TUint8 ch) + /** + Convert a single hex char from ascii + */ +{ + // convert to lowercase + if((ch >= 'A') && (ch <= 'F')) + { + ch -= ('A' -'a'); + } + // Handle a-f + if((ch >= 'a') && (ch <= 'f')) + { + return ch - 'a' + 10; + } + + // Handle 0-9 + if((ch >= '0') && (ch <= '9')) + { + return ch - '0'; + } + + // Illegal + FatalError(); + return 0xff; +} + +EncDecContainerItem::~EncDecContainerItem() +{ +} + + +#ifdef _BullseyeCoverage +#pragma BullseyeCoverage off +#endif +std::string EncDecContainerItem::ItemName() const +{ + // Should never be called + exit(-1); + std::string tmp; + return tmp; +} + +void EncDecContainerItem::SetItemName(const std::string &) +{ + // Should never be called + exit(-1); +} +#ifdef _BullseyeCoverage +#pragma BullseyeCoverage restore +#endif + + + +EncDecContainer::EncDecContainer(const char *aContainerName, EncDecContainerItemFactoryFunc *aFactory) + : iName(aContainerName), iFactory(aFactory), iArray() +{ +} + +EncDecContainer::~EncDecContainer() +{ + reset(); +} + +void EncDecContainer::push_back(EncDecContainerItem *aItem) +{ + iArray.push_back(aItem); +} + +const EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) const +{ + return *iArray[aIndex]; +} + +EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) +{ + return *iArray[aIndex]; +} + +TUint32 EncDecContainer::size() const +{ + return iArray.size(); +} + +void EncDecContainer::reset() +{ + while(!iArray.empty()) + { + EncDecContainerItem *p = iArray.back(); + iArray.pop_back(); + delete p; + } +} + + + +void EncDecContainer::Encode(REncodeWriteStream &aWriteStream) const +{ + // Calculate Start/End container names + std::string startName("Start"); + startName.append(iName); + std::string endName("End"); + endName.append(iName); + + prog << Log::Indent() << "Writing " << startName << Log::Endl(); + + TUint32 arrayLength = iArray.size(); + + if(aWriteStream.HumanReadable()) + { + // Human + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(startName.data(), startName.size()); + aWriteStream.WriteLineEnd(); + } + else + { + // Binary + // Write length of array + aWriteStream.WriteBin(&arrayLength, sizeof(arrayLength)); + } + + aWriteStream.IncIndent(); + + // Write array entries + for(TUint32 i=0; i < arrayLength; ++i) + { + std::ostringstream entryComment; + entryComment << "# Entry " << i+1; + prog << Log::Indent() << entryComment.str() << Log::Endl(); + + bool bracketItem = (iArray[i]->ItemType() != 0); + if(aWriteStream.HumanReadable()) + { + if(bracketItem) + { + std::ostringstream itemStart; + itemStart << "Start" << iArray[i]->ItemType() << " " << iArray[i]->ItemName(); + prog << Log::Indent() << itemStart.str() << Log::Endl(); + + aWriteStream.WriteIndent(); + aWriteStream.WriteCStr("Start"); + aWriteStream.WriteCStr(iArray[i]->ItemType()); + aWriteStream.WriteCStr(" \""); + aWriteStream.WriteQuotedUtf8(iArray[i]->ItemName().data(), iArray[i]->ItemName().size()); + aWriteStream.WriteCStr("\""); + aWriteStream.WriteLineEnd(); + } + else + { + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(entryComment.str().data(), entryComment.str().size()); + aWriteStream.WriteLineEnd(); + } + } + aWriteStream.IncIndent(); + iArray[i]->Encode(aWriteStream); + aWriteStream.DecIndent(); + if(bracketItem && aWriteStream.HumanReadable()) + { + std::ostringstream tmp; + tmp << "End" << iArray[i]->ItemType(); + + prog << Log::Indent() << tmp.str() << Log::Endl(); + + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(tmp.str().data(), tmp.str().size()); + aWriteStream.WriteLineEnd(); + } + } + + aWriteStream.DecIndent(); + + if(aWriteStream.HumanReadable()) + { + // Human + aWriteStream.WriteIndent(); + aWriteStream.WriteCStr("End"); + aWriteStream.WriteBin(iName.data(), iName.size()); + aWriteStream.WriteLineEnd(); + } + + prog << Log::Indent() << endName << Log::Endl(); + + return; +} + +void EncDecContainer::Decode(RDecodeReadStream &aReadStream) +{ + // Calculate Start/End container names + std::string startName("Start"); + startName.append(iName); + std::string endName("End"); + endName.append(iName); + + prog << Log::Indent() << "Reading " << startName << Log::Endl(); + + if(aReadStream.HumanReadable()) + { + // Human + + // Check/consume container StartX + aReadStream.CheckName(startName); + + prog.IncIndent(); + + // Create items until we find the container EndX + TUint32 entryNum=1; + while(aReadStream.PeakToken() != endName) + { + // Progress message + prog << Log::Indent() << "# Entry " << std::dec << entryNum++ << std::hex << Log::Endl(); + + EncDecContainerItem *item = iFactory(); + bool bracketedItem = (item->ItemType() != 0); + std::string itemName; + if(bracketedItem && aReadStream.HumanReadable()) + { + // Bracketed item, so read ItemType tag and ItemName + std::string itemStart("Start"); + itemStart.append(item->ItemType()); + aReadStream.CheckName(itemStart); + prog << Log::Indent() << itemStart; + + // Read item name + aReadStream.ReadNextToken(); + itemName = aReadStream.Token(); + } + + prog.IncIndent(); + item->Decode(aReadStream); + iArray.push_back(item); + prog.DecIndent(); + if(bracketedItem && aReadStream.HumanReadable()) + { + // Bracketed item, so read End ItemType tag + std::string itemEnd("End"); + itemEnd.append(item->ItemType()); + aReadStream.CheckName(itemEnd); + // and set item name + item->SetItemName(itemName); + } + } + + // Check/consume container EndX + aReadStream.CheckName(endName); + + prog.DecIndent(); + } + else + { + // Binary + // Read number of entries + TUint32 arrayLength; + aReadStream.RawRead(&arrayLength, sizeof(arrayLength)); + + prog.IncIndent(); + for(TUint32 i=0; i < arrayLength; ++i) + { + EncDecContainerItem *item = iFactory(); + prog << Log::Indent() << "# Entry " << std::dec << i+1 << std::hex << Log::Endl(); + prog.IncIndent(); + item->Decode(aReadStream); + prog.DecIndent(); + iArray.push_back(item); + } + prog.DecIndent(); + } + + prog << Log::Indent() << endName << Log::Endl(); + +} + + + + +REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecContainer &aContainer) +{ + aContainer.Encode(aStream); + return aStream; +} + +RDecodeReadStream& operator>>(RDecodeReadStream& aStream,EncDecContainer &aContainer) +{ + aContainer.Decode(aStream); + return aStream; +} + +// +// TUid +// +void EncodeHuman(REncodeWriteStream& aStream,const TUid &aUid) +{ + aStream.WriteHexNumber(aUid.iUid); +} +void DecodeHuman(RDecodeReadStream& aStream,TUid &aUid) +{ + aUid.iUid = aStream.ReadUnsignedNumber(sizeof(aUid.iUid)); +} + +// +// TName +// +void EncodeHuman(REncodeWriteStream& aStream,const TName &aName) +{ + // Compress the internal UTF-16 to human readable UTF-8 + ; + TInt outputBytes = 0; + TUint8 *outBuf = cstrFromUtf16(aName.Ptr(), aName.Length(), outputBytes); + + aStream.WriteByte('"'); + aStream.WriteQuotedUtf8(outBuf, outputBytes); + aStream.WriteByte('"'); + + delete [] outBuf; +} +void DecodeHuman(RDecodeReadStream& aStream,TName &aName) +{ + aStream.ReadNextToken(); + + // Expand UTF-8 into internal UTF-16LE representation + TInt outputWords = 0; + TText *outputBuf = utf16FromUtf8((const TUint8 *)aStream.Token().data(), aStream.Token().size(), outputWords); + memcpy((void *)aName.Ptr(), outputBuf, outputWords*2); + aName.SetLength(outputWords); + delete [] outputBuf; +} + +void readContainer(const std::string &aFileName, bool aHuman, EncDecContainer &container) +{ + if(aHuman) + { + FileReadStream fileReadStream(aFileName, true); + std::string certBaseName(aFileName); + size_t dotLoc = certBaseName.rfind('.'); + if(dotLoc != std::string::npos) + { + certBaseName.erase(dotLoc); + } + certBaseName += '_'; + RDecodeReadStream inStream(certBaseName, fileReadStream); // human readable + inStream >> container; + inStream.Close(); + } + else + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + CPermanentFileStore* store = CPermanentFileStore::OpenLC(fs, _L16(aFileName.c_str()),EFileShareAny | EFileRead); + store->SetTypeL(KPermanentFileStoreLayoutUid); + + RStoreReadStream rootStream; + rootStream.OpenLC(*store, store->Root()); + TUint32 dataStreamId; + rootStream >> dataStreamId; + CleanupStack::PopAndDestroy(&rootStream); + + RStoreReadStream dataStream; + dataStream.OpenLC(*store, dataStreamId); + + RDecodeReadStream readStream(store, dataStream); // binary store + + readStream >> container; + + CleanupStack::PopAndDestroy(&dataStream); + CleanupStack::PopAndDestroy(store); + CleanupStack::PopAndDestroy(&fs); + } +} + + +void writeContainer(const char *aFileName, bool aHuman, bool aPemOut, bool aVerbose, const EncDecContainer &container) +{ + prog << Log::Indent() << "Writing output file '" << aFileName << "'" << Log::Endl(); + prog.IncIndent(); + if(aHuman) + { + FileWriteStream fileWriteStream(aFileName); + // Calculate based name by striping last .xx extension and appending an underscore. + std::string certBaseName(aFileName); + size_t dotLoc = certBaseName.rfind('.'); + if(dotLoc != std::string::npos) + { + certBaseName.erase(dotLoc); + } + certBaseName += '_'; + + REncodeWriteStream outStream(certBaseName, fileWriteStream); // human readable + outStream.PemOut() = aPemOut; + outStream.Verbose() = aVerbose; + outStream << container; + outStream.Close(); + } + else + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + CFileStore* store = CPermanentFileStore::ReplaceLC(fs,_L16(aFileName),EFileShareAny | EFileRead | EFileWrite); + store->SetTypeL(KPermanentFileStoreLayoutUid); + + RStoreWriteStream dataStream; + TStreamId dataStreamId = dataStream.CreateLC(*store); + + REncodeWriteStream outStream(store, dataStream); // binary + outStream << container; + outStream.Close(); + + dataStream.CommitL(); + dataStream.Close(); + + RStoreWriteStream rootStream; + TStreamId rootId = rootStream.CreateLC(*store); + rootStream << dataStreamId; + rootStream.CommitL(); + rootStream.Close(); + + + store->SetRootL(rootId); + store->CommitL(); + CleanupStack::PopAndDestroy(&dataStream); + CleanupStack::PopAndDestroy(store); + CleanupStack::PopAndDestroy(&fs); + } + prog.DecIndent(); +} + + +// End of file