--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp Wed Jul 08 11:25:26 2009 +0100
@@ -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 <sstream>
+#include <errno.h>
+#include <s32ucmp.h>
+#include "stringconv.h"
+#include <stdio.h>
+#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; i<iIndentLevel; ++i)
+ {
+ WriteByte('\t');
+ }
+}
+
+void REncodeWriteStream::IncIndent()
+{
+ prog.IncIndent();
+ ++iIndentLevel;
+BULLSEYE_OFF
+ if(iIndentLevel < 0) FatalError();
+BULLSEYE_RESTORE
+}
+
+void REncodeWriteStream::DecIndent()
+{
+ prog.DecIndent();
+ --iIndentLevel;
+BULLSEYE_OFF
+ if(iIndentLevel < 0) FatalError();
+BULLSEYE_RESTORE
+}
+
+bool REncodeWriteStream::HumanReadable() const
+{
+ return iHumanReadable;
+}
+
+bool &REncodeWriteStream::PemOut()
+{
+ return iPemOut;
+}
+
+bool &REncodeWriteStream::Verbose()
+{
+ return iVerbose;
+}
+
+
+
+std::string REncodeWriteStream::CertFileName(TUint32 aFormat, TUint32 aCertNumber)
+{
+ std::stringstream ss;
+ ss << iCertBaseName;
+ ss << "cert";
+ ss << aCertNumber;
+ if(aFormat == EX509Certificate)
+ {
+ if(iPemOut)
+ {
+ ss << ".pem";
+ }
+ else
+ {
+ ss << ".der";
+ }
+ }
+ else
+ {
+ ss << ".dat";
+ }
+
+ return ss.str();
+}
+
+
+
+void REncodeWriteStream::Close()
+{
+BULLSEYE_OFF
+ if(iWriteStream)
+BULLSEYE_RESTORE
+ {
+ iWriteStream->Close();
+ }
+}
+
+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