--- a/securityanddataprivacytools/securitytools/certapp/certapp.cpp Tue Jul 21 01:04:32 2009 +0100
+++ b/securityanddataprivacytools/securitytools/certapp/certapp.cpp Thu Sep 10 14:01:51 2009 +0300
@@ -1,1046 +1,1046 @@
-/*
-* 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:
-*
-*/
-
-
-static const char * const sVersion = "certapp version 1.1.++";
-#include <e32base.h>
-#include <f32file.h>
-#include <s32file.h>
-#include <map>
-#include <sys/stat.h>
-#include "encdec.h"
-#include "certclients.h"
-#include "filecertstore.h"
-#include "swicertstore.h"
-#include "logger.h"
-#include "stringconv.h"
-#include <errno.h>
-#include "appuidmap.h"
-#include "openssl_license.h"
-#include "utils.h"
-
-#ifdef __TOOLS2_LINUX__
-#include <unistd.h>
-#include <stdio.h>
-#else
-#include <io.h>
-#endif // __TOOLS2_LINUX__
-
-#ifdef __TOOLS2_LINUX__
-#define DIR_SEPARATOR "/"
-#else
-#define DIR_SEPARATOR "\\"
-#endif
-
-enum CertStoreFileType
-{
- EBinCertClients,
- EHumanCertClients,
- EBinFileCertStore,
- EHumanFileCertStore,
- EBinSwiCertStore,
- EHumanSwiCertStore
-};
-
-struct AppMapEntry
- {
- TUint32 iUid;
- TUint32 iInputFileIndex;
- };
-typedef std::map<std::string, AppMapEntry> AppMap;
-
-typedef std::map<std::string, TUint32> FCSLabelMap; // maps cert label to inputFileIndex
-
-typedef std::vector<std::string> StringVector;
-typedef std::vector<CertStoreFileType> CertStoreFileTypeVector;
-
-void ProcessCommandLine(int aArgc, char **aArgv,
- StringVector &aInputFiles,
- StringVector &aInputDirs,
- CertStoreFileTypeVector &aInputFileTypes,
- StringVector &aOutputFiles,
- StringVector &aOutputDirs,
- CertStoreFileTypeVector &aOutputFileTypes,
- bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates);
-
-void ProcessCertClientFiles(const std::string &aBaseDir,
- const StringVector &aInputFiles,
- const StringVector &aInputDirs,
- const CertStoreFileTypeVector &aInputFileTypes,
- bool &aAllowDuplicates,
- EncDecContainer &aCertAppInfoContainer);
-
-void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
- const EncDecContainer &aFileCertStoreContainer,
- const EncDecContainer &aSwiCertStoreContainer,
- const std::string &aBaseDir,
- const StringVector &aOutputFiles,
- const StringVector &aOutputDirs,
- const CertStoreFileTypeVector &aOutputFileTypes,
- bool aVerbose, bool aPemOut);
-
-bool ValidateLabel(FCSLabelMap &aLabelMap,
- const StringVector &aInputFiles,
- CertStoreFileType aFileType,
- TUint32 aFileIndex,
- const TCertLabel &aCertLabel);
-
-
-struct SubjectToSubjectKeyIdEntry
- {
- bool iDuplicate;
- std::string iLabel;
- TKeyIdentifier iSubjectKeyIdentifier;
- };
-typedef std::map<std::string, SubjectToSubjectKeyIdEntry> SubjectToSubjectKeyIdMap;
-void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
- SubjectToSubjectKeyIdMap &aSubjectMap);
-
-void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap,
- EUseCertificateExtension aUseExtension,
- EncDecContainer &aCertStoreContainer);
-
-static const std::string OPT_PROGRESS("--progress=");
-static const std::string OPT_ERRORS("--errors=");
-static const std::string OPT_VERBOSE("--verbose");
-static const std::string OPT_ALLOWDUPLICATES("--allowduplicates");
-static const std::string OPT_CHDIR("--chdir=");
-static const std::string OPT_HCERTCLIENTS_L("--hcertclients=");
-static const std::string OPT_HCERTCLIENTS_S("--hcc=");
-static const std::string OPT_BCERTCLIENTS_L("--bcertclients=");
-static const std::string OPT_BCERTCLIENTS_S("--bcc=");
-static const std::string OPT_HFILECERTSTORE_L("--hfilecertstore=");
-static const std::string OPT_HFILECERTSTORE_S("--hca=");
-static const std::string OPT_BFILECERTSTORE_L("--bfilecertstore=");
-static const std::string OPT_BFILECERTSTORE_S("--bca=");
-static const std::string OPT_HSWICERTSTORE_L("--hswicertstore=");
-static const std::string OPT_HSWICERTSTORE_S("--hswi=");
-static const std::string OPT_BSWICERTSTORE_L("--bswicertstore=");
-static const std::string OPT_BSWICERTSTORE_S("--bswi=");
-
-
-
-void usage()
-{
- prog << "certapp: general_options file_options --out file_options" << Log::Endl();
- prog << Log::Endl();
- prog << "Basic usage is to give one or more input files of any supported type, followed by --out and a list of output files using the same syntax" << Log::Endl();
- prog << "Typically at least one input file of type certclients should be given (via --bcertclients or --hcertclients) because this is required to encode/decode the application usage fields in the swicertstore and filecertstore files." << Log::Endl();
- prog << Log::Endl();
- prog << "general_options contains one or more of the following options:-" << Log::Endl();
- prog << "\t--help|-h\tDisplay this usage message" << Log::Endl();
- prog << "\t" << OPT_PROGRESS << "filename\tSave progress output to specified file" << Log::Endl();
- prog << "\t" << OPT_ERRORS << "filename\tSave error output to specified file" << Log::Endl();
- prog << "\t" << OPT_VERBOSE << "Include additional debug comments in output files" << Log::Endl();
- prog << "\t--license Display license information" << Log::Endl();
- prog << "\t--pemout Output certificates in PEM format (nb. format is auto-detected when reading)" << Log::Endl();
- prog << "\t" << OPT_ALLOWDUPLICATES << "\tWhen reading human readable config files, permit adding duplicate certificate labels in stores and UIDs in certclients (testing ONLY)" << Log::Endl();
- prog << "An errors/progress filename of - will write to the standard output." << Log::Endl();
- prog << "If the errors/progress filenames are identical, the output will be merged." << Log::Endl();
- prog << Log::Endl();
- prog << "Both instances of file_options contains one or more of the following options:-" << Log::Endl();
- prog << "\t" << OPT_HCERTCLIENTS_L << "|" << OPT_HCERTCLIENTS_S << "filename\t\tHuman readable certclients file" << Log::Endl();
- prog << "\t" << OPT_BCERTCLIENTS_L << "|" << OPT_BCERTCLIENTS_S << "filename\t\tBinary certclients file" << Log::Endl();
- prog << Log::Endl();
- prog << "\t" << OPT_HFILECERTSTORE_L << "|" << OPT_HFILECERTSTORE_S << "filename\tHuman readable filecertstore" << Log::Endl();
- prog << "\t" << OPT_BFILECERTSTORE_L << "|" << OPT_BFILECERTSTORE_S << "filename\tBinary filecertstore" << Log::Endl();
- prog << Log::Endl();
- prog << "\t" << OPT_HSWICERTSTORE_L << "|" << OPT_HSWICERTSTORE_S << "filename\tHuman readable swicertstore" << Log::Endl();
- prog << "\t" << OPT_BSWICERTSTORE_L << "|" << OPT_BSWICERTSTORE_S << "filename\tBinary swicertstore" << Log::Endl();
- prog << Log::Endl();
- prog << "\t" << "--out Change to specifying output files" << Log::Endl();
- prog << "\t" << "--in Change to specifying input files" << Log::Endl();
- prog << "\t" << "--chdir=relativeDir Change to the specified dir. Can be specified multiple times. Missing dir will be created if only last element is missing." << Log::Endl();
- prog << Log::Endl();
-
- prog << "Examples" << Log::Endl();
- prog << "Read/dump a swicertstore" << Log::Endl();
- prog << "\tcertapp --bcertclients=certclients.dat --bswicertstore=swicertstore.dat --out --hswicertstore=swicertstore.txt" << Log::Endl();
- prog << "Read/dump a filecertstore" << Log::Endl();
- prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --out --hfilecertstore=cacerts.txt" << Log::Endl();
- prog << "Augment a filecertstore" << Log::Endl();
- prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --hfilecertstore=cacerts_extras.txt --out --bfilecertstore=cacerts_new.dat" << Log::Endl();
- prog << Log::Endl();
- prog << "Device file locations" << Log::Endl();
- prog << "ROM swicertstore - z:\\resource\\swicertstore.dat" << Log::Endl();
- prog << "Writable swicertstore - !:\\resource\\swicertstore\\dat\\* where ! is the system drive" << Log::Endl();
- prog << "Initial filecertstore and certclients z:\\private\\101f72a6\\cacerts.dat and certclients.dat. Copied to sys drive on first use." << Log::Endl();
- prog << "Filecertstore !:\\private\\101f72a6\\cacerts.dat and certclients.dat. where ! is the system drive." << Log::Endl();
-}
-
-void ChangeDir(const std::string &aBaseDir, const std::string &aRelativeDir)
-{
- std::string dir(aBaseDir);
- if(aRelativeDir != ".")
- {
- // Build dir to create and change into
- dir.append(DIR_SEPARATOR);
- dir.append(aRelativeDir);
- }
-
- prog << Log::Indent() << "Setting dir to " << dir << Log::Endl();
-#ifdef __LINUX__
- (void) mkdir(dir.c_str(),0755); // May already exist so no need to check return code
-#else
- (void) mkdir(dir.c_str()); // May already exist so no need to check return code
-#endif
- if(chdir(dir.c_str()) < 0)
- {
- dbg << Log::Indent() << "failed to change dir to " << dir << Log::Endl();
- FatalError();
- }
- return;
-}
-
-int main(int argc, char **argv)
-{
- dbg.SetStream(&std::cout);
- prog.SetStream(&std::cout);
-
- try{
- if(argc==1)
- {
- prog << sVersion << " Use -h for help." << Log::Endl();
- }
-
- StringVector inputFiles;
- StringVector inputDirs;
- CertStoreFileTypeVector inputFileTypes;
-
- StringVector outputFiles;
- StringVector outputDirs;
- CertStoreFileTypeVector outputFileTypes;
-
-
- bool verbose = false;
- bool pemOut = false;
- bool allowDuplicates = false;
-
- // Process all the command line options and file arguments
- ProcessCommandLine(argc, argv,
- inputFiles, inputDirs, inputFileTypes,
- outputFiles, outputDirs, outputFileTypes,
- verbose, pemOut, allowDuplicates);
-
-
- // Save current directory
- std::string baseDir;
- {
- char tmp[FILENAME_MAX];
- if(getcwd(tmp, FILENAME_MAX) == 0)
- {
- dbg << Log::Indent() << "Failed to read current dir" << Log::Endl();
- FatalError();
- }
- baseDir = tmp;
- }
-
-
- //
- // Process input files starting with certclient files and working from right to left
- //
- EncDecContainer certAppInfoContainer("ClientInfo", CertificateAppInfo::Factory);
- ProcessCertClientFiles(baseDir, inputFiles, inputDirs, inputFileTypes,
- allowDuplicates,
- certAppInfoContainer);
-
-
- // Generate config data for application uid EncDecEnum object in AppUidListEntry
- AppUidMap::GenerateEnumEntries();
-
- //
- // Process remaining input files working from right to left
- //
- EncDecContainer fileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
- FCSLabelMap fcsLabels;
- EncDecContainer swiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
- FCSLabelMap swiLabels;
- for(int fileIndex = inputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
- {
- CertStoreFileType fileType = inputFileTypes[fileIndex];
- if((fileType == EBinFileCertStore) || (fileType == EHumanFileCertStore))
- {
- // Change to correct directory
- ChangeDir(baseDir, inputDirs[fileIndex]);
-
- EncDecContainer tmpFileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
- if(fileType == EBinFileCertStore)
- {
- prog << "Reading binary filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(inputFiles[fileIndex], false, tmpFileCertStoreContainer);
- }
- if(fileType == EHumanFileCertStore)
- {
- prog << "Reading human filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(inputFiles[fileIndex], true, tmpFileCertStoreContainer);
- }
-
- // Now merge the new file into the running store.
- prog << Log::Indent() << "Merging filecertstore data" << Log::Endl();
- AutoIndent ai(prog);
- for(TUint32 entryIndex = 0; entryIndex < tmpFileCertStoreContainer.size(); ++entryIndex)
- {
- const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(tmpFileCertStoreContainer[entryIndex]);
- std::string nname = stringFromUtf16(entry.Label());
-
- if(!ValidateLabel(fcsLabels, inputFiles, fileType, fileIndex, entry.Label()))
- {
- // Duplicate detected
- if(!allowDuplicates || (fileType == EBinFileCertStore))
- {
- continue; // Skip adding duplicate
- }
- // Only allow duplicates if debugging and reading
- // human readable config file.
- dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
- }
-
- // Add entry
- CertStoreEntry *newEntry = new CertStoreEntry;
- *newEntry = entry;
- fileCertStoreContainer.push_back(newEntry);
- }
- continue;
- }
-
-
- if((fileType == EBinSwiCertStore) || (fileType == EHumanSwiCertStore))
- {
- // Change to correct directory
- ChangeDir(baseDir, inputDirs[fileIndex]);
-
- EncDecContainer tmpSwiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
- if(fileType == EBinSwiCertStore)
- {
- prog << "Reading binary swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(inputFiles[fileIndex], false, tmpSwiCertStoreContainer);
- }
- if(fileType == EHumanSwiCertStore)
- {
- prog << "Reading human swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(inputFiles[fileIndex], true, tmpSwiCertStoreContainer);
- }
-
- // Now merge the new file into the running store.
- prog << Log::Indent() << "Merging swicerstore data" << Log::Endl();
- AutoIndent ai(prog);
- for(TUint32 entryIndex = 0; entryIndex < tmpSwiCertStoreContainer.size(); ++entryIndex)
- {
- const SwiCertStoreEntry &entry = static_cast<const SwiCertStoreEntry &>(tmpSwiCertStoreContainer[entryIndex]);
- std::string nname = stringFromUtf16(entry.Label());
-
- if(!ValidateLabel(swiLabels, inputFiles, fileType, fileIndex, entry.Label()))
- {
- // Duplicate detected
- if(!allowDuplicates || (fileType == EBinSwiCertStore))
- {
- continue; // Skip adding duplicate
- }
- // Only allow duplicates if debugging and reading
- // human readable config file.
- dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
- }
-
- // Add entry
- SwiCertStoreEntry *newEntry = new SwiCertStoreEntry;
- *newEntry = entry;
- swiCertStoreContainer.push_back(newEntry);
- }
- continue;
- }
- }
-
- // Fix Certificate IDs in fileCertStoreContainer
- for(TUint32 entryIndex=0; entryIndex < fileCertStoreContainer.size(); ++entryIndex)
- {
- CertStoreEntry &entry = static_cast<CertStoreEntry &>(fileCertStoreContainer[entryIndex]);
- entry.Info().SetOutputCertificateId(entryIndex);
- }
-
- // Fix Certificate IDs in swicertstore container.
- for(TUint32 entryIndex=0; entryIndex < swiCertStoreContainer.size(); ++entryIndex)
- {
- SwiCertStoreEntry &entry = static_cast<SwiCertStoreEntry &>(swiCertStoreContainer[entryIndex]);
- entry.Info().SetOutputCertificateId(entryIndex);
- }
-
- //
- // Fix auto IssuerKeyId values
- //
- SubjectToSubjectKeyIdMap subjectMap;
- //
- // Fix IssuerKeyId values in swiCertStoreContainer
- //
- // We do not use the AuthorityKeyId extension and only consider
- // certificates in swi certstores.
- //
- // First map all the SWI certificate subject names to SubjectKeyId values
- BuildSubjectToSubjectKeyIdMap(swiCertStoreContainer, subjectMap);
- // Now update IssuerKeyId fields which are set to auto.
- // The AuthorityKeyId extension value will be ignored.
- // The SubjectKeyId of a matching certificate (if there is a
- // single match on issuer name) in the swi cert store will be
- // used.
- SetIssuerKeyId(subjectMap, KIgnoreCertificateExtension, swiCertStoreContainer);
-
-
- //
- // Fix IssuerKeyId values in fileCertStoreContainer
- //
- // Add all filecertstore certificates to the
- // subjectName/SubjectKeyId map
- BuildSubjectToSubjectKeyIdMap(fileCertStoreContainer, subjectMap);
- // Now update IssuerKeyId fields which are set to auto. If an the
- // AuthorityKeyId extension is present and <160bits use it,
- // otherwise use the SubjectKeyId of the matching certificate (if
- // there is a single match on issuer name).
- SetIssuerKeyId(subjectMap, KUseCertificateExtension, fileCertStoreContainer);
-
- //
- // Now generate output files
- //
- GenerateOutputFiles(certAppInfoContainer, fileCertStoreContainer, swiCertStoreContainer,
- baseDir, outputFiles, outputDirs, outputFileTypes, verbose, pemOut);
-
-
- }
- catch(...)
- {
- dbg << Log::Indent() << "C++ expection!" << Log::Endl();
- FatalError();
- }
-
- prog << Log::Indent() << "Normal exit" << Log::Endl();
- prog.Stream().flush();
- dbg.Stream().flush();
- return 0; // All ok
-}
-
-/**
- ProcessCommandLine
-*/
-void ProcessCommandLine(int aArgc, char **aArgv,
- StringVector &aInputFiles, StringVector &aInputDirs, CertStoreFileTypeVector &aInputFileTypes,
- StringVector &aOutputFiles, StringVector &aOutputDirs, CertStoreFileTypeVector &aOutputFileTypes,
- bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates)
-{
- std::string progressFile("-");
- static std::fstream sProgressStream;
-
- std::string dbgFile("-");
- static std::fstream sDbgStream;
-
- StringVector *files = &aInputFiles;
- StringVector *dirs = &aInputDirs;
- CertStoreFileTypeVector *fileTypes = &aInputFileTypes;
-
- int argIndex=1;
- // Process overall arguments (-h --progress --errors)
- for(; argIndex < aArgc; ++argIndex)
- {
- std::string arg(aArgv[argIndex]);
-
- if(arg == "--license")
- {
- prog << sVersion << Log::Endl();
- prog << "Copyright (c) 2008 Symbian Software Ltd. All rights reserved." << Log::Endl();
- prog << "Linked against openssl. Credits and license for openssl follow:-" << Log::Endl();
- prog << openssl_license << Log::Endl();
-
- continue;
- }
-
- if(arg == OPT_VERBOSE)
- {
- prog << "Enabling additional output file comments" << Log::Endl();
- aVerbose = true;
-
- continue;
- }
-
- if(arg == "--pemout")
- {
- prog << "Setting output certificate format to PEM" << Log::Endl();
- aPemOut = true;
-
- continue;
- }
-
- if(arg == OPT_ALLOWDUPLICATES)
- {
- prog << "Allowing addition of duplicate labels in stores and UIDs in certclients when reading human readable input (testing ONLY)" << Log::Endl();
- aAllowDuplicates = true;
-
- continue;
- }
-
- if((arg.find(OPT_PROGRESS) == 0) ||
- (arg.find(OPT_ERRORS) == 0))
- {
- // The following logic is required so that if both streams
- // are set to the same destination we share a streams
- // object and hence avoid buffering issues.
- std::string *thisFile;
- std::fstream *thisStream;
- Log *thisLog;
- std::string *otherFile;
- std::fstream *otherStream;
- Log *otherLog;
-
- if(arg.find(OPT_PROGRESS) == 0)
- {
- thisFile = &progressFile;
- thisStream = &sProgressStream;
- thisLog = &prog;
- otherFile = &dbgFile;
- otherStream = &sDbgStream;
- otherLog = &dbg;
-
- *thisFile = arg.substr(OPT_PROGRESS.size(), arg.npos);
- }
- else
- {
- thisFile = &dbgFile;
- thisStream = &sDbgStream;
- thisLog = &dbg;
- otherFile = &progressFile;
- otherStream = &sProgressStream;
- otherLog = &prog;
-
- *thisFile = arg.substr(OPT_ERRORS.size(), arg.npos);
- }
-
- if(*thisFile == *otherFile)
- {
- // Reuse existing stream. This avoids two streams opening the same file...
- thisLog->SetStream(&otherLog->Stream());
- continue;
- }
-
- // Need to open a new stream
- if(thisStream->is_open()) thisStream->close();
- if(*thisFile == "-")
- {
- thisLog->SetStream(&std::cout);
- continue;
- }
-
- OpenUtf8FStreamForWrite(*thisStream, thisFile->c_str());
- if(thisStream->fail())
- {
- if(thisLog == &dbg)
- {
- dbg.SetStream(&std::cout);
- }
- dbg << Log::Indent() << "Failed to open log file specified by " << aArgv[argIndex-1] << " '" << *thisFile << "'" << Log::Endl();
- return;
- }
- thisLog->SetStream(thisStream);
- continue;
- }
-
- if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
- {
- usage();
- continue;
- }
-
- // Not a general option, probably an input file...
- break;
- }
-
- // Process main arguments
- for(; argIndex < aArgc; ++argIndex)
- {
- std::string arg(aArgv[argIndex]);
-
- bool gotFile = false;
- if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
- {
- usage();
- continue;
- }
-
- if(arg.find(OPT_CHDIR) == 0)
- {
- dirs->push_back(arg.substr(OPT_CHDIR.size(), arg.npos));
- // Move to next option
- ++argIndex;
- if(argIndex >= aArgc) break;
- arg = aArgv[argIndex];
- }
- else
- {
- dirs->push_back(".");
- }
-
- std::string fileArg;
- if(arg.find(OPT_BCERTCLIENTS_L) == 0)
- {
- fileTypes->push_back(EBinCertClients);
- fileArg = arg.substr(OPT_BCERTCLIENTS_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_BCERTCLIENTS_S) == 0)
- {
- fileTypes->push_back(EBinCertClients);
- fileArg = arg.substr(OPT_BCERTCLIENTS_S.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HCERTCLIENTS_L) == 0)
- {
- fileTypes->push_back(EHumanCertClients);
- fileArg = arg.substr(OPT_HCERTCLIENTS_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HCERTCLIENTS_S) == 0)
- {
- fileTypes->push_back(EHumanCertClients);
- fileArg = arg.substr(OPT_HCERTCLIENTS_S.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_BFILECERTSTORE_L) == 0)
- {
- fileTypes->push_back(EBinFileCertStore);
- fileArg = arg.substr(OPT_BFILECERTSTORE_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_BFILECERTSTORE_S) == 0)
- {
- fileTypes->push_back(EBinFileCertStore);
- fileArg = arg.substr(OPT_BFILECERTSTORE_S.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HFILECERTSTORE_L) == 0)
- {
- fileTypes->push_back(EHumanFileCertStore);
- fileArg = arg.substr(OPT_HFILECERTSTORE_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HFILECERTSTORE_S) == 0)
- {
- fileTypes->push_back(EHumanFileCertStore);
- fileArg = arg.substr(OPT_HFILECERTSTORE_S.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_BSWICERTSTORE_L) == 0)
- {
- fileTypes->push_back(EBinSwiCertStore);
- fileArg = arg.substr(OPT_BSWICERTSTORE_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_BSWICERTSTORE_S) == 0)
- {
- fileTypes->push_back(EBinSwiCertStore);
- fileArg = arg.substr(OPT_BSWICERTSTORE_S.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HSWICERTSTORE_L) == 0)
- {
- fileTypes->push_back(EHumanSwiCertStore);
- fileArg = arg.substr(OPT_HSWICERTSTORE_L.size(), arg.npos);
- gotFile = true;
- }
- if(arg.find(OPT_HSWICERTSTORE_S) == 0)
- {
- fileTypes->push_back(EHumanSwiCertStore);
- fileArg = arg.substr(OPT_HSWICERTSTORE_S.size(), arg.npos);
- gotFile = true;
- }
-
- if(arg.find("--out") == 0)
- {
- files = &aOutputFiles;
- dirs = &aOutputDirs;
- fileTypes = &aOutputFileTypes;
- continue;
- }
-
- if(arg.find("--in") == 0)
- {
- files = &aInputFiles;
- dirs = &aInputDirs;
- fileTypes = &aInputFileTypes;
- continue;
- }
-
- if(gotFile)
- {
- files->push_back(fileArg);
- continue;
- }
-
- usage();
- dbg << Log::Indent() << "Unknown option " << (const char *) aArgv[argIndex] << Log::Endl();
- FatalError();
- }
- return;
-}
-
-void ProcessCertClientFiles(const std::string &aBaseDir,
- const StringVector &aInputFiles,
- const StringVector &aInputDirs,
- const CertStoreFileTypeVector &aInputFileTypes,
- bool &aAllowDuplicates,
- EncDecContainer &aCertAppInfoContainer)
-{
- AppMap appMap;
- for(int fileIndex = aInputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
- {
- CertStoreFileType fileType = aInputFileTypes[fileIndex];
- if((fileType != EBinCertClients) && (fileType != EHumanCertClients))
- {
- continue;
- }
-
- // Change to correct directory
- ChangeDir(aBaseDir, aInputDirs[fileIndex]);
-
- EncDecContainer tmpCertInfoContainer("ClientInfo", CertificateAppInfo::Factory);
-
- if(fileType == EBinCertClients)
- {
- prog << Log::Indent() << "Reading binary certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(aInputFiles[fileIndex], false, tmpCertInfoContainer);
- }
- else
- {
- prog << Log::Indent() << "Reading human certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
- AutoIndent ai(prog);
- readContainer(aInputFiles[fileIndex], true, tmpCertInfoContainer);
- }
-
- // Now merge the new file into the running store.
- prog << Log::Indent() << "Merging certclients data" << Log::Endl();
- AutoIndent ai(prog);
- AutoIndent ai2(dbg);
- for(TUint32 entryIndex = 0; entryIndex < tmpCertInfoContainer.size(); ++entryIndex)
- {
- const CertificateAppInfo &info = static_cast<const CertificateAppInfo &>(tmpCertInfoContainer[entryIndex]);
- std::string nname = stringFromUtf16(info.Name());
- //prog << Log::Indent() << "checking " << nname << Log::Endl();
-
-
- TInt32 lastIndex;
- std::string firstDef;
- if(!AppUidMap::InsertUidDefinition(info.Id().iUid, nname, fileIndex,
- lastIndex, firstDef))
- {
- // Duplicate entry for UID
- if(nname == firstDef)
- {
- // But both entries have the same value
- prog << Log::Indent() << "Duplicate, but identical, entries for UID 0x" << info.Id().iUid << " '" << nname << "'." << Log::Endl();
- AutoIndent ai(prog);
- prog << Log::Indent() << "From files '" << aInputFiles[lastIndex] << "' and '" << aInputFiles[fileIndex] << "'." << Log::Endl();
- }
- else
- {
- // Entries have different values
- dbg << Log::Indent() << "DUPLICATE entry for UID 0x" << info.Id().iUid << Log::Endl();
- AutoIndent ai(dbg);
- dbg << Log::Indent() << "Ignoring '" << nname << "' from '" << aInputFiles[fileIndex] << "'." << Log::Endl();
- dbg << Log::Indent() << "Keeping '" << firstDef << "' from '" << aInputFiles[lastIndex] << "'." << Log::Endl();
- if(lastIndex == fileIndex)
- {
- if(fileType == EBinCertClients)
- {
- dbg << Log::Indent() << "Both entries are in the same binary same file!" << Log::Endl();
- continue; // Skip adding duplicate
- }
- dbg << Log::Indent() << "Clash is within a single text configuration file!" << Log::Endl();
- if(!aAllowDuplicates)
- {
- FatalError();
- }
- }
- }
-
- // Only add duplicates when debugging and the add is
- // from a human readable config file.
- if(!aAllowDuplicates || (fileType != EHumanCertClients))
- {
- continue; // Skip adding duplicate
- }
- dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
- }
-
- // Add entry
- CertificateAppInfo *newInfo = new CertificateAppInfo;
- *newInfo = info;
- aCertAppInfoContainer.push_back(newInfo);
- }
- }
-}
-
-
-
-/**
- Write output files to disk
- */
-void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
- const EncDecContainer &aFileCertStoreContainer,
- const EncDecContainer &aSwiCertStoreContainer,
- const std::string &aBaseDir,
- const StringVector &aOutputFiles,
- const StringVector &aOutputDirs,
- const CertStoreFileTypeVector &aOutputFileTypes,
- bool aVerbose, bool aPemOut)
-{
- for(int fileIndex = aOutputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
- {
- // Change to correct directory
- ChangeDir(aBaseDir, aOutputDirs[fileIndex]);
-
- CertStoreFileType fileType = aOutputFileTypes[fileIndex];
- //
- // Set the container and write mode to use
- //
- const EncDecContainer *container = 0;
- bool humanReadable = false;
- if(fileType == EBinCertClients)
- {
- container = &aCertAppInfoContainer;
- humanReadable = false;
- }
- if(fileType == EHumanCertClients)
- {
- container = &aCertAppInfoContainer;
- humanReadable = true;
- }
- if(fileType == EBinFileCertStore)
- {
- container = &aFileCertStoreContainer;
- humanReadable = false;
- }
- if(fileType == EHumanFileCertStore)
- {
- container = &aFileCertStoreContainer;
- humanReadable = true;
- }
- if(fileType == EBinSwiCertStore)
- {
- container = &aSwiCertStoreContainer;
- humanReadable = false;
- }
- if(fileType == EHumanSwiCertStore)
- {
- container = &aSwiCertStoreContainer;
- humanReadable = true;
- }
-
- if(container == 0)
- {
- // failed to decode the output file type!
- FatalError();
- }
- //
- // Write the container out
- //
- writeContainer(aOutputFiles[fileIndex].c_str(), humanReadable, aPemOut, aVerbose, *container);
- }
- return;
-}
-
-
-
-/**
- ValidateLabel
-
- This function maintains a map of certificate labels to input file
- (ie file index) and definition.
-
- If the label is NOT already defined in the map, then the function
- returns true, which instructs the caller to include the
- label/certificate in the generated store.
-
- If the label is already defined in the map, then the function
- returns false, which instructs the caller to NOT include the
- label/certificate in the generated store.
-
- The files on the command line are processed right to left, so if
- multiple definitions (for the same label) are seen, only the first
- will be included in the generated store.
-
- The information saved in the map is used to generate helpful
- warning/error messages as follows:-
-
- 1) The saved definition is the first definition encountered, and is
- therefore the one which has been included in the store.
-
- 2) The saved file index is the index of the LAST file processed
- containing a definition for this label. This may be different to
- the one containing the first definition.
-
- Consider the following sequence:-
-
- First processed file - Definition for label Fred
- Second processed file - Another two definitions for label Fred
-
- When processing the third definition (in the second file), the
- saved file index will be that of the second file. The code uses
- this to check if there are multiple definitions within a SINGLE
- input file, for the same label.
-
- If the multiple definitions are within a single human readable
- file, then this is considered a fatal error, otherwise only a
- warning is generated.
-
- Duplicate definitions in different files, generate a warning.
- */
-bool ValidateLabel(FCSLabelMap &aLabelMap,
- const StringVector &aInputFiles,
- CertStoreFileType aFileType,
- TUint32 aFileIndex,
- const TCertLabel &aCertLabel)
-{
- std::string nname = stringFromUtf16(aCertLabel);
- FCSLabelMap::value_type e(nname, aFileIndex);
- std::pair<FCSLabelMap::iterator,bool> result = aLabelMap.insert(e);
- if(result.second == true)
- {
- // Not a duplicate
- return true;
- }
-
- // Duplicate label entry
- dbg << Log::Indent() << "DUPLICATE label detected in '" << aInputFiles[aFileIndex] << "'." << Log::Endl();
- AutoIndent ai(dbg);
- dbg << Log::Indent() << "Duplicate entry for '" << e.first << "' ignored. Keeping entry from '" << aInputFiles[(*result.first).second] << "'" <<Log::Endl();
- if((result.first)->second == TUint32(aFileIndex))
- {
- dbg << Log::Indent() << "Both entries are in the same file." << Log::Endl();
- if((aFileType == EHumanFileCertStore) || (aFileType == EHumanSwiCertStore))
- {
- dbg << Log::Indent() << "FATAL error - Clash is within a single text configuration file - aborting!" << Log::Endl();
- FatalError();
- }
- return false; // Insert failed, keep earlier def
- }
- else
- {
- // Update file index for last definition. This is used to
- // detect if the last two defs were within a single file.
- (result.first)->second = TUint32(aFileIndex);
- return false; // Insert failed, keep earlier def
- }
- return false;
-}
-
-void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
- SubjectToSubjectKeyIdMap &aSubjectMap)
-{
- // Collect subjectName/SubjectKeyId for all certs
- for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
- {
- const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(aCertStoreContainer[entryIndex]);
- if(entry.Info().CertificateFormat() != EX509Certificate)
- {
- continue;
- }
-
- std::pair<SubjectToSubjectKeyIdMap::key_type, SubjectToSubjectKeyIdMap::mapped_type> e;
- e.first = entry.CertSubject();
- e.second.iDuplicate = false;
- e.second.iLabel = stringFromUtf16(entry.Label());
- e.second.iSubjectKeyIdentifier = entry.Info().SubjectKeyId().iHash;
- std::pair<SubjectToSubjectKeyIdMap::iterator, bool> result = aSubjectMap.insert(e);
- if(result.second == false)
- {
- dbg << Log::Indent() << "WARNING: Certificate '" << e.second.iLabel << "' has a subject name of '" << e.first << "' which clashes with certificate '" << (*result.first).second.iLabel <<"'" << Log::Endl();
- (*result.first).second.iDuplicate = true;
- }
- }
-
-}
-
-
-void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap,
- EUseCertificateExtension aUseExtension,
- EncDecContainer &aCertStoreContainer)
-{
- // Now loop across certs setting the issuer key id.
- for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
- {
- CertStoreEntry &entry = static_cast<CertStoreEntry &>(aCertStoreContainer[entryIndex]);
- if(entry.Info().CertificateFormat() != EX509Certificate)
- {
- continue;
- }
- if(!entry.Info().IssuerKeyId().iAutoKey)
- {
- continue;
- }
-
- std::string certLabel = stringFromUtf16(entry.Label());
-
- prog << Log::Indent() << "Attempting to auto set IssuerIeyId for '" << certLabel << "'" << Log::Endl();
-
- AutoIndent ai(prog);
-
- // Lookup issuer key id in certificate extension and if found use that.
- //
- // X509IssuerKeyId will always set the issuerName.
- // If aIgnoreExtension is false, then it will attempt to read
- // the AuthorityKeyId extension. If found (and <160bits), it
- // will write the ID to issuerId and return true.
- // Otherwise it will return false.
- // Certificate read errors are fatal.
- std::string issuerName;
- TKeyIdentifier issuerId;
- if(X509IssuerKeyId(aUseExtension,
- entry.CertData(), entry.Info().CertSize(),
- issuerName, issuerId))
- {
- // There is an authority key id extension so use its value
- prog << Log::Indent() << "Using value from certificate '" << certLabel << "' extension" << Log::Endl();
- entry.Info().IssuerKeyId().iHash = issuerId;
- }
- else
- {
- // No extension so lookup issuerName in the map
- prog << Log::Indent() << "Looking up issuer '" << issuerName << "' in map" << Log::Endl();
- SubjectToSubjectKeyIdMap::const_iterator it = aSubjectMap.find(issuerName);
- if(it == aSubjectMap.end())
- {
- prog << Log::Indent() << "Not found - Using empty IssuerKeyId " << Log::Endl();
- }
- else
- {
- if((*it).second.iDuplicate)
- {
- prog << Log::Indent() << "Found - but multiple certs with matching subject name - Using empty IssuerKeyId" << Log::Endl();
- }
- else
- {
- prog << Log::Indent() << "Found - Using Subject Key of matching cert" << Log::Endl();
- entry.Info().IssuerKeyId().iHash = (*it).second.iSubjectKeyIdentifier;
- }
- }
- }
- }
-
-}
-
-
-
-// End of file
+/*
+* 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:
+*
+*/
+
+
+static const char * const sVersion = "certapp version 1.1.++";
+#include <e32base.h>
+#include <f32file.h>
+#include <s32file.h>
+#include <map>
+#include <sys/stat.h>
+#include "encdec.h"
+#include "certclients.h"
+#include "filecertstore.h"
+#include "swicertstore.h"
+#include "logger.h"
+#include "stringconv.h"
+#include <errno.h>
+#include "appuidmap.h"
+#include "openssl_license.h"
+#include "utils.h"
+
+#ifdef __TOOLS2_LINUX__
+#include <unistd.h>
+#include <stdio.h>
+#else
+#include <io.h>
+#endif // __TOOLS2_LINUX__
+
+#ifdef __TOOLS2_LINUX__
+#define DIR_SEPARATOR "/"
+#else
+#define DIR_SEPARATOR "\\"
+#endif
+
+enum CertStoreFileType
+{
+ EBinCertClients,
+ EHumanCertClients,
+ EBinFileCertStore,
+ EHumanFileCertStore,
+ EBinSwiCertStore,
+ EHumanSwiCertStore
+};
+
+struct AppMapEntry
+ {
+ TUint32 iUid;
+ TUint32 iInputFileIndex;
+ };
+typedef std::map<std::string, AppMapEntry> AppMap;
+
+typedef std::map<std::string, TUint32> FCSLabelMap; // maps cert label to inputFileIndex
+
+typedef std::vector<std::string> StringVector;
+typedef std::vector<CertStoreFileType> CertStoreFileTypeVector;
+
+void ProcessCommandLine(int aArgc, char **aArgv,
+ StringVector &aInputFiles,
+ StringVector &aInputDirs,
+ CertStoreFileTypeVector &aInputFileTypes,
+ StringVector &aOutputFiles,
+ StringVector &aOutputDirs,
+ CertStoreFileTypeVector &aOutputFileTypes,
+ bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates);
+
+void ProcessCertClientFiles(const std::string &aBaseDir,
+ const StringVector &aInputFiles,
+ const StringVector &aInputDirs,
+ const CertStoreFileTypeVector &aInputFileTypes,
+ bool &aAllowDuplicates,
+ EncDecContainer &aCertAppInfoContainer);
+
+void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
+ const EncDecContainer &aFileCertStoreContainer,
+ const EncDecContainer &aSwiCertStoreContainer,
+ const std::string &aBaseDir,
+ const StringVector &aOutputFiles,
+ const StringVector &aOutputDirs,
+ const CertStoreFileTypeVector &aOutputFileTypes,
+ bool aVerbose, bool aPemOut);
+
+bool ValidateLabel(FCSLabelMap &aLabelMap,
+ const StringVector &aInputFiles,
+ CertStoreFileType aFileType,
+ TUint32 aFileIndex,
+ const TCertLabel &aCertLabel);
+
+
+struct SubjectToSubjectKeyIdEntry
+ {
+ bool iDuplicate;
+ std::string iLabel;
+ TKeyIdentifier iSubjectKeyIdentifier;
+ };
+typedef std::map<std::string, SubjectToSubjectKeyIdEntry> SubjectToSubjectKeyIdMap;
+void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
+ SubjectToSubjectKeyIdMap &aSubjectMap);
+
+void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap,
+ EUseCertificateExtension aUseExtension,
+ EncDecContainer &aCertStoreContainer);
+
+static const std::string OPT_PROGRESS("--progress=");
+static const std::string OPT_ERRORS("--errors=");
+static const std::string OPT_VERBOSE("--verbose");
+static const std::string OPT_ALLOWDUPLICATES("--allowduplicates");
+static const std::string OPT_CHDIR("--chdir=");
+static const std::string OPT_HCERTCLIENTS_L("--hcertclients=");
+static const std::string OPT_HCERTCLIENTS_S("--hcc=");
+static const std::string OPT_BCERTCLIENTS_L("--bcertclients=");
+static const std::string OPT_BCERTCLIENTS_S("--bcc=");
+static const std::string OPT_HFILECERTSTORE_L("--hfilecertstore=");
+static const std::string OPT_HFILECERTSTORE_S("--hca=");
+static const std::string OPT_BFILECERTSTORE_L("--bfilecertstore=");
+static const std::string OPT_BFILECERTSTORE_S("--bca=");
+static const std::string OPT_HSWICERTSTORE_L("--hswicertstore=");
+static const std::string OPT_HSWICERTSTORE_S("--hswi=");
+static const std::string OPT_BSWICERTSTORE_L("--bswicertstore=");
+static const std::string OPT_BSWICERTSTORE_S("--bswi=");
+
+
+
+void usage()
+{
+ prog << "certapp: general_options file_options --out file_options" << Log::Endl();
+ prog << Log::Endl();
+ prog << "Basic usage is to give one or more input files of any supported type, followed by --out and a list of output files using the same syntax" << Log::Endl();
+ prog << "Typically at least one input file of type certclients should be given (via --bcertclients or --hcertclients) because this is required to encode/decode the application usage fields in the swicertstore and filecertstore files." << Log::Endl();
+ prog << Log::Endl();
+ prog << "general_options contains one or more of the following options:-" << Log::Endl();
+ prog << "\t--help|-h\tDisplay this usage message" << Log::Endl();
+ prog << "\t" << OPT_PROGRESS << "filename\tSave progress output to specified file" << Log::Endl();
+ prog << "\t" << OPT_ERRORS << "filename\tSave error output to specified file" << Log::Endl();
+ prog << "\t" << OPT_VERBOSE << "Include additional debug comments in output files" << Log::Endl();
+ prog << "\t--license Display license information" << Log::Endl();
+ prog << "\t--pemout Output certificates in PEM format (nb. format is auto-detected when reading)" << Log::Endl();
+ prog << "\t" << OPT_ALLOWDUPLICATES << "\tWhen reading human readable config files, permit adding duplicate certificate labels in stores and UIDs in certclients (testing ONLY)" << Log::Endl();
+ prog << "An errors/progress filename of - will write to the standard output." << Log::Endl();
+ prog << "If the errors/progress filenames are identical, the output will be merged." << Log::Endl();
+ prog << Log::Endl();
+ prog << "Both instances of file_options contains one or more of the following options:-" << Log::Endl();
+ prog << "\t" << OPT_HCERTCLIENTS_L << "|" << OPT_HCERTCLIENTS_S << "filename\t\tHuman readable certclients file" << Log::Endl();
+ prog << "\t" << OPT_BCERTCLIENTS_L << "|" << OPT_BCERTCLIENTS_S << "filename\t\tBinary certclients file" << Log::Endl();
+ prog << Log::Endl();
+ prog << "\t" << OPT_HFILECERTSTORE_L << "|" << OPT_HFILECERTSTORE_S << "filename\tHuman readable filecertstore" << Log::Endl();
+ prog << "\t" << OPT_BFILECERTSTORE_L << "|" << OPT_BFILECERTSTORE_S << "filename\tBinary filecertstore" << Log::Endl();
+ prog << Log::Endl();
+ prog << "\t" << OPT_HSWICERTSTORE_L << "|" << OPT_HSWICERTSTORE_S << "filename\tHuman readable swicertstore" << Log::Endl();
+ prog << "\t" << OPT_BSWICERTSTORE_L << "|" << OPT_BSWICERTSTORE_S << "filename\tBinary swicertstore" << Log::Endl();
+ prog << Log::Endl();
+ prog << "\t" << "--out Change to specifying output files" << Log::Endl();
+ prog << "\t" << "--in Change to specifying input files" << Log::Endl();
+ prog << "\t" << "--chdir=relativeDir Change to the specified dir. Can be specified multiple times. Missing dir will be created if only last element is missing." << Log::Endl();
+ prog << Log::Endl();
+
+ prog << "Examples" << Log::Endl();
+ prog << "Read/dump a swicertstore" << Log::Endl();
+ prog << "\tcertapp --bcertclients=certclients.dat --bswicertstore=swicertstore.dat --out --hswicertstore=swicertstore.txt" << Log::Endl();
+ prog << "Read/dump a filecertstore" << Log::Endl();
+ prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --out --hfilecertstore=cacerts.txt" << Log::Endl();
+ prog << "Augment a filecertstore" << Log::Endl();
+ prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --hfilecertstore=cacerts_extras.txt --out --bfilecertstore=cacerts_new.dat" << Log::Endl();
+ prog << Log::Endl();
+ prog << "Device file locations" << Log::Endl();
+ prog << "ROM swicertstore - z:\\resource\\swicertstore.dat" << Log::Endl();
+ prog << "Writable swicertstore - !:\\resource\\swicertstore\\dat\\* where ! is the system drive" << Log::Endl();
+ prog << "Initial filecertstore and certclients z:\\private\\101f72a6\\cacerts.dat and certclients.dat. Copied to sys drive on first use." << Log::Endl();
+ prog << "Filecertstore !:\\private\\101f72a6\\cacerts.dat and certclients.dat. where ! is the system drive." << Log::Endl();
+}
+
+void ChangeDir(const std::string &aBaseDir, const std::string &aRelativeDir)
+{
+ std::string dir(aBaseDir);
+ if(aRelativeDir != ".")
+ {
+ // Build dir to create and change into
+ dir.append(DIR_SEPARATOR);
+ dir.append(aRelativeDir);
+ }
+
+ prog << Log::Indent() << "Setting dir to " << dir << Log::Endl();
+#ifdef __LINUX__
+ (void) mkdir(dir.c_str(),0755); // May already exist so no need to check return code
+#else
+ (void) mkdir(dir.c_str()); // May already exist so no need to check return code
+#endif
+ if(chdir(dir.c_str()) < 0)
+ {
+ dbg << Log::Indent() << "failed to change dir to " << dir << Log::Endl();
+ FatalError();
+ }
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ dbg.SetStream(&std::cout);
+ prog.SetStream(&std::cout);
+
+ try{
+ if(argc==1)
+ {
+ prog << sVersion << " Use -h for help." << Log::Endl();
+ }
+
+ StringVector inputFiles;
+ StringVector inputDirs;
+ CertStoreFileTypeVector inputFileTypes;
+
+ StringVector outputFiles;
+ StringVector outputDirs;
+ CertStoreFileTypeVector outputFileTypes;
+
+
+ bool verbose = false;
+ bool pemOut = false;
+ bool allowDuplicates = false;
+
+ // Process all the command line options and file arguments
+ ProcessCommandLine(argc, argv,
+ inputFiles, inputDirs, inputFileTypes,
+ outputFiles, outputDirs, outputFileTypes,
+ verbose, pemOut, allowDuplicates);
+
+
+ // Save current directory
+ std::string baseDir;
+ {
+ char tmp[FILENAME_MAX];
+ if(getcwd(tmp, FILENAME_MAX) == 0)
+ {
+ dbg << Log::Indent() << "Failed to read current dir" << Log::Endl();
+ FatalError();
+ }
+ baseDir = tmp;
+ }
+
+
+ //
+ // Process input files starting with certclient files and working from right to left
+ //
+ EncDecContainer certAppInfoContainer("ClientInfo", CertificateAppInfo::Factory);
+ ProcessCertClientFiles(baseDir, inputFiles, inputDirs, inputFileTypes,
+ allowDuplicates,
+ certAppInfoContainer);
+
+
+ // Generate config data for application uid EncDecEnum object in AppUidListEntry
+ AppUidMap::GenerateEnumEntries();
+
+ //
+ // Process remaining input files working from right to left
+ //
+ EncDecContainer fileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
+ FCSLabelMap fcsLabels;
+ EncDecContainer swiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
+ FCSLabelMap swiLabels;
+ for(int fileIndex = inputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
+ {
+ CertStoreFileType fileType = inputFileTypes[fileIndex];
+ if((fileType == EBinFileCertStore) || (fileType == EHumanFileCertStore))
+ {
+ // Change to correct directory
+ ChangeDir(baseDir, inputDirs[fileIndex]);
+
+ EncDecContainer tmpFileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
+ if(fileType == EBinFileCertStore)
+ {
+ prog << "Reading binary filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(inputFiles[fileIndex], false, tmpFileCertStoreContainer);
+ }
+ if(fileType == EHumanFileCertStore)
+ {
+ prog << "Reading human filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(inputFiles[fileIndex], true, tmpFileCertStoreContainer);
+ }
+
+ // Now merge the new file into the running store.
+ prog << Log::Indent() << "Merging filecertstore data" << Log::Endl();
+ AutoIndent ai(prog);
+ for(TUint32 entryIndex = 0; entryIndex < tmpFileCertStoreContainer.size(); ++entryIndex)
+ {
+ const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(tmpFileCertStoreContainer[entryIndex]);
+ std::string nname = stringFromUtf16(entry.Label());
+
+ if(!ValidateLabel(fcsLabels, inputFiles, fileType, fileIndex, entry.Label()))
+ {
+ // Duplicate detected
+ if(!allowDuplicates || (fileType == EBinFileCertStore))
+ {
+ continue; // Skip adding duplicate
+ }
+ // Only allow duplicates if debugging and reading
+ // human readable config file.
+ dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
+ }
+
+ // Add entry
+ CertStoreEntry *newEntry = new CertStoreEntry;
+ *newEntry = entry;
+ fileCertStoreContainer.push_back(newEntry);
+ }
+ continue;
+ }
+
+
+ if((fileType == EBinSwiCertStore) || (fileType == EHumanSwiCertStore))
+ {
+ // Change to correct directory
+ ChangeDir(baseDir, inputDirs[fileIndex]);
+
+ EncDecContainer tmpSwiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
+ if(fileType == EBinSwiCertStore)
+ {
+ prog << "Reading binary swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(inputFiles[fileIndex], false, tmpSwiCertStoreContainer);
+ }
+ if(fileType == EHumanSwiCertStore)
+ {
+ prog << "Reading human swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(inputFiles[fileIndex], true, tmpSwiCertStoreContainer);
+ }
+
+ // Now merge the new file into the running store.
+ prog << Log::Indent() << "Merging swicerstore data" << Log::Endl();
+ AutoIndent ai(prog);
+ for(TUint32 entryIndex = 0; entryIndex < tmpSwiCertStoreContainer.size(); ++entryIndex)
+ {
+ const SwiCertStoreEntry &entry = static_cast<const SwiCertStoreEntry &>(tmpSwiCertStoreContainer[entryIndex]);
+ std::string nname = stringFromUtf16(entry.Label());
+
+ if(!ValidateLabel(swiLabels, inputFiles, fileType, fileIndex, entry.Label()))
+ {
+ // Duplicate detected
+ if(!allowDuplicates || (fileType == EBinSwiCertStore))
+ {
+ continue; // Skip adding duplicate
+ }
+ // Only allow duplicates if debugging and reading
+ // human readable config file.
+ dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
+ }
+
+ // Add entry
+ SwiCertStoreEntry *newEntry = new SwiCertStoreEntry;
+ *newEntry = entry;
+ swiCertStoreContainer.push_back(newEntry);
+ }
+ continue;
+ }
+ }
+
+ // Fix Certificate IDs in fileCertStoreContainer
+ for(TUint32 entryIndex=0; entryIndex < fileCertStoreContainer.size(); ++entryIndex)
+ {
+ CertStoreEntry &entry = static_cast<CertStoreEntry &>(fileCertStoreContainer[entryIndex]);
+ entry.Info().SetOutputCertificateId(entryIndex);
+ }
+
+ // Fix Certificate IDs in swicertstore container.
+ for(TUint32 entryIndex=0; entryIndex < swiCertStoreContainer.size(); ++entryIndex)
+ {
+ SwiCertStoreEntry &entry = static_cast<SwiCertStoreEntry &>(swiCertStoreContainer[entryIndex]);
+ entry.Info().SetOutputCertificateId(entryIndex);
+ }
+
+ //
+ // Fix auto IssuerKeyId values
+ //
+ SubjectToSubjectKeyIdMap subjectMap;
+ //
+ // Fix IssuerKeyId values in swiCertStoreContainer
+ //
+ // We do not use the AuthorityKeyId extension and only consider
+ // certificates in swi certstores.
+ //
+ // First map all the SWI certificate subject names to SubjectKeyId values
+ BuildSubjectToSubjectKeyIdMap(swiCertStoreContainer, subjectMap);
+ // Now update IssuerKeyId fields which are set to auto.
+ // The AuthorityKeyId extension value will be ignored.
+ // The SubjectKeyId of a matching certificate (if there is a
+ // single match on issuer name) in the swi cert store will be
+ // used.
+ SetIssuerKeyId(subjectMap, KIgnoreCertificateExtension, swiCertStoreContainer);
+
+
+ //
+ // Fix IssuerKeyId values in fileCertStoreContainer
+ //
+ // Add all filecertstore certificates to the
+ // subjectName/SubjectKeyId map
+ BuildSubjectToSubjectKeyIdMap(fileCertStoreContainer, subjectMap);
+ // Now update IssuerKeyId fields which are set to auto. If an the
+ // AuthorityKeyId extension is present and <160bits use it,
+ // otherwise use the SubjectKeyId of the matching certificate (if
+ // there is a single match on issuer name).
+ SetIssuerKeyId(subjectMap, KUseCertificateExtension, fileCertStoreContainer);
+
+ //
+ // Now generate output files
+ //
+ GenerateOutputFiles(certAppInfoContainer, fileCertStoreContainer, swiCertStoreContainer,
+ baseDir, outputFiles, outputDirs, outputFileTypes, verbose, pemOut);
+
+
+ }
+ catch(...)
+ {
+ dbg << Log::Indent() << "C++ expection!" << Log::Endl();
+ FatalError();
+ }
+
+ prog << Log::Indent() << "Normal exit" << Log::Endl();
+ prog.Stream().flush();
+ dbg.Stream().flush();
+ return 0; // All ok
+}
+
+/**
+ ProcessCommandLine
+*/
+void ProcessCommandLine(int aArgc, char **aArgv,
+ StringVector &aInputFiles, StringVector &aInputDirs, CertStoreFileTypeVector &aInputFileTypes,
+ StringVector &aOutputFiles, StringVector &aOutputDirs, CertStoreFileTypeVector &aOutputFileTypes,
+ bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates)
+{
+ std::string progressFile("-");
+ static std::fstream sProgressStream;
+
+ std::string dbgFile("-");
+ static std::fstream sDbgStream;
+
+ StringVector *files = &aInputFiles;
+ StringVector *dirs = &aInputDirs;
+ CertStoreFileTypeVector *fileTypes = &aInputFileTypes;
+
+ int argIndex=1;
+ // Process overall arguments (-h --progress --errors)
+ for(; argIndex < aArgc; ++argIndex)
+ {
+ std::string arg(aArgv[argIndex]);
+
+ if(arg == "--license")
+ {
+ prog << sVersion << Log::Endl();
+ prog << "Copyright (c) 2008 Symbian Software Ltd. All rights reserved." << Log::Endl();
+ prog << "Linked against openssl. Credits and license for openssl follow:-" << Log::Endl();
+ prog << openssl_license << Log::Endl();
+
+ continue;
+ }
+
+ if(arg == OPT_VERBOSE)
+ {
+ prog << "Enabling additional output file comments" << Log::Endl();
+ aVerbose = true;
+
+ continue;
+ }
+
+ if(arg == "--pemout")
+ {
+ prog << "Setting output certificate format to PEM" << Log::Endl();
+ aPemOut = true;
+
+ continue;
+ }
+
+ if(arg == OPT_ALLOWDUPLICATES)
+ {
+ prog << "Allowing addition of duplicate labels in stores and UIDs in certclients when reading human readable input (testing ONLY)" << Log::Endl();
+ aAllowDuplicates = true;
+
+ continue;
+ }
+
+ if((arg.find(OPT_PROGRESS) == 0) ||
+ (arg.find(OPT_ERRORS) == 0))
+ {
+ // The following logic is required so that if both streams
+ // are set to the same destination we share a streams
+ // object and hence avoid buffering issues.
+ std::string *thisFile;
+ std::fstream *thisStream;
+ Log *thisLog;
+ std::string *otherFile;
+ std::fstream *otherStream;
+ Log *otherLog;
+
+ if(arg.find(OPT_PROGRESS) == 0)
+ {
+ thisFile = &progressFile;
+ thisStream = &sProgressStream;
+ thisLog = &prog;
+ otherFile = &dbgFile;
+ otherStream = &sDbgStream;
+ otherLog = &dbg;
+
+ *thisFile = arg.substr(OPT_PROGRESS.size(), arg.npos);
+ }
+ else
+ {
+ thisFile = &dbgFile;
+ thisStream = &sDbgStream;
+ thisLog = &dbg;
+ otherFile = &progressFile;
+ otherStream = &sProgressStream;
+ otherLog = &prog;
+
+ *thisFile = arg.substr(OPT_ERRORS.size(), arg.npos);
+ }
+
+ if(*thisFile == *otherFile)
+ {
+ // Reuse existing stream. This avoids two streams opening the same file...
+ thisLog->SetStream(&otherLog->Stream());
+ continue;
+ }
+
+ // Need to open a new stream
+ if(thisStream->is_open()) thisStream->close();
+ if(*thisFile == "-")
+ {
+ thisLog->SetStream(&std::cout);
+ continue;
+ }
+
+ OpenUtf8FStreamForWrite(*thisStream, thisFile->c_str());
+ if(thisStream->fail())
+ {
+ if(thisLog == &dbg)
+ {
+ dbg.SetStream(&std::cout);
+ }
+ dbg << Log::Indent() << "Failed to open log file specified by " << aArgv[argIndex-1] << " '" << *thisFile << "'" << Log::Endl();
+ return;
+ }
+ thisLog->SetStream(thisStream);
+ continue;
+ }
+
+ if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
+ {
+ usage();
+ continue;
+ }
+
+ // Not a general option, probably an input file...
+ break;
+ }
+
+ // Process main arguments
+ for(; argIndex < aArgc; ++argIndex)
+ {
+ std::string arg(aArgv[argIndex]);
+
+ bool gotFile = false;
+ if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
+ {
+ usage();
+ continue;
+ }
+
+ if(arg.find(OPT_CHDIR) == 0)
+ {
+ dirs->push_back(arg.substr(OPT_CHDIR.size(), arg.npos));
+ // Move to next option
+ ++argIndex;
+ if(argIndex >= aArgc) break;
+ arg = aArgv[argIndex];
+ }
+ else
+ {
+ dirs->push_back(".");
+ }
+
+ std::string fileArg;
+ if(arg.find(OPT_BCERTCLIENTS_L) == 0)
+ {
+ fileTypes->push_back(EBinCertClients);
+ fileArg = arg.substr(OPT_BCERTCLIENTS_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_BCERTCLIENTS_S) == 0)
+ {
+ fileTypes->push_back(EBinCertClients);
+ fileArg = arg.substr(OPT_BCERTCLIENTS_S.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HCERTCLIENTS_L) == 0)
+ {
+ fileTypes->push_back(EHumanCertClients);
+ fileArg = arg.substr(OPT_HCERTCLIENTS_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HCERTCLIENTS_S) == 0)
+ {
+ fileTypes->push_back(EHumanCertClients);
+ fileArg = arg.substr(OPT_HCERTCLIENTS_S.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_BFILECERTSTORE_L) == 0)
+ {
+ fileTypes->push_back(EBinFileCertStore);
+ fileArg = arg.substr(OPT_BFILECERTSTORE_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_BFILECERTSTORE_S) == 0)
+ {
+ fileTypes->push_back(EBinFileCertStore);
+ fileArg = arg.substr(OPT_BFILECERTSTORE_S.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HFILECERTSTORE_L) == 0)
+ {
+ fileTypes->push_back(EHumanFileCertStore);
+ fileArg = arg.substr(OPT_HFILECERTSTORE_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HFILECERTSTORE_S) == 0)
+ {
+ fileTypes->push_back(EHumanFileCertStore);
+ fileArg = arg.substr(OPT_HFILECERTSTORE_S.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_BSWICERTSTORE_L) == 0)
+ {
+ fileTypes->push_back(EBinSwiCertStore);
+ fileArg = arg.substr(OPT_BSWICERTSTORE_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_BSWICERTSTORE_S) == 0)
+ {
+ fileTypes->push_back(EBinSwiCertStore);
+ fileArg = arg.substr(OPT_BSWICERTSTORE_S.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HSWICERTSTORE_L) == 0)
+ {
+ fileTypes->push_back(EHumanSwiCertStore);
+ fileArg = arg.substr(OPT_HSWICERTSTORE_L.size(), arg.npos);
+ gotFile = true;
+ }
+ if(arg.find(OPT_HSWICERTSTORE_S) == 0)
+ {
+ fileTypes->push_back(EHumanSwiCertStore);
+ fileArg = arg.substr(OPT_HSWICERTSTORE_S.size(), arg.npos);
+ gotFile = true;
+ }
+
+ if(arg.find("--out") == 0)
+ {
+ files = &aOutputFiles;
+ dirs = &aOutputDirs;
+ fileTypes = &aOutputFileTypes;
+ continue;
+ }
+
+ if(arg.find("--in") == 0)
+ {
+ files = &aInputFiles;
+ dirs = &aInputDirs;
+ fileTypes = &aInputFileTypes;
+ continue;
+ }
+
+ if(gotFile)
+ {
+ files->push_back(fileArg);
+ continue;
+ }
+
+ usage();
+ dbg << Log::Indent() << "Unknown option " << (const char *) aArgv[argIndex] << Log::Endl();
+ FatalError();
+ }
+ return;
+}
+
+void ProcessCertClientFiles(const std::string &aBaseDir,
+ const StringVector &aInputFiles,
+ const StringVector &aInputDirs,
+ const CertStoreFileTypeVector &aInputFileTypes,
+ bool &aAllowDuplicates,
+ EncDecContainer &aCertAppInfoContainer)
+{
+ AppMap appMap;
+ for(int fileIndex = aInputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
+ {
+ CertStoreFileType fileType = aInputFileTypes[fileIndex];
+ if((fileType != EBinCertClients) && (fileType != EHumanCertClients))
+ {
+ continue;
+ }
+
+ // Change to correct directory
+ ChangeDir(aBaseDir, aInputDirs[fileIndex]);
+
+ EncDecContainer tmpCertInfoContainer("ClientInfo", CertificateAppInfo::Factory);
+
+ if(fileType == EBinCertClients)
+ {
+ prog << Log::Indent() << "Reading binary certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(aInputFiles[fileIndex], false, tmpCertInfoContainer);
+ }
+ else
+ {
+ prog << Log::Indent() << "Reading human certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
+ AutoIndent ai(prog);
+ readContainer(aInputFiles[fileIndex], true, tmpCertInfoContainer);
+ }
+
+ // Now merge the new file into the running store.
+ prog << Log::Indent() << "Merging certclients data" << Log::Endl();
+ AutoIndent ai(prog);
+ AutoIndent ai2(dbg);
+ for(TUint32 entryIndex = 0; entryIndex < tmpCertInfoContainer.size(); ++entryIndex)
+ {
+ const CertificateAppInfo &info = static_cast<const CertificateAppInfo &>(tmpCertInfoContainer[entryIndex]);
+ std::string nname = stringFromUtf16(info.Name());
+ //prog << Log::Indent() << "checking " << nname << Log::Endl();
+
+
+ TInt32 lastIndex;
+ std::string firstDef;
+ if(!AppUidMap::InsertUidDefinition(info.Id().iUid, nname, fileIndex,
+ lastIndex, firstDef))
+ {
+ // Duplicate entry for UID
+ if(nname == firstDef)
+ {
+ // But both entries have the same value
+ prog << Log::Indent() << "Duplicate, but identical, entries for UID 0x" << info.Id().iUid << " '" << nname << "'." << Log::Endl();
+ AutoIndent ai(prog);
+ prog << Log::Indent() << "From files '" << aInputFiles[lastIndex] << "' and '" << aInputFiles[fileIndex] << "'." << Log::Endl();
+ }
+ else
+ {
+ // Entries have different values
+ dbg << Log::Indent() << "DUPLICATE entry for UID 0x" << info.Id().iUid << Log::Endl();
+ AutoIndent ai(dbg);
+ dbg << Log::Indent() << "Ignoring '" << nname << "' from '" << aInputFiles[fileIndex] << "'." << Log::Endl();
+ dbg << Log::Indent() << "Keeping '" << firstDef << "' from '" << aInputFiles[lastIndex] << "'." << Log::Endl();
+ if(lastIndex == fileIndex)
+ {
+ if(fileType == EBinCertClients)
+ {
+ dbg << Log::Indent() << "Both entries are in the same binary same file!" << Log::Endl();
+ continue; // Skip adding duplicate
+ }
+ dbg << Log::Indent() << "Clash is within a single text configuration file!" << Log::Endl();
+ if(!aAllowDuplicates)
+ {
+ FatalError();
+ }
+ }
+ }
+
+ // Only add duplicates when debugging and the add is
+ // from a human readable config file.
+ if(!aAllowDuplicates || (fileType != EHumanCertClients))
+ {
+ continue; // Skip adding duplicate
+ }
+ dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
+ }
+
+ // Add entry
+ CertificateAppInfo *newInfo = new CertificateAppInfo;
+ *newInfo = info;
+ aCertAppInfoContainer.push_back(newInfo);
+ }
+ }
+}
+
+
+
+/**
+ Write output files to disk
+ */
+void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
+ const EncDecContainer &aFileCertStoreContainer,
+ const EncDecContainer &aSwiCertStoreContainer,
+ const std::string &aBaseDir,
+ const StringVector &aOutputFiles,
+ const StringVector &aOutputDirs,
+ const CertStoreFileTypeVector &aOutputFileTypes,
+ bool aVerbose, bool aPemOut)
+{
+ for(int fileIndex = aOutputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
+ {
+ // Change to correct directory
+ ChangeDir(aBaseDir, aOutputDirs[fileIndex]);
+
+ CertStoreFileType fileType = aOutputFileTypes[fileIndex];
+ //
+ // Set the container and write mode to use
+ //
+ const EncDecContainer *container = 0;
+ bool humanReadable = false;
+ if(fileType == EBinCertClients)
+ {
+ container = &aCertAppInfoContainer;
+ humanReadable = false;
+ }
+ if(fileType == EHumanCertClients)
+ {
+ container = &aCertAppInfoContainer;
+ humanReadable = true;
+ }
+ if(fileType == EBinFileCertStore)
+ {
+ container = &aFileCertStoreContainer;
+ humanReadable = false;
+ }
+ if(fileType == EHumanFileCertStore)
+ {
+ container = &aFileCertStoreContainer;
+ humanReadable = true;
+ }
+ if(fileType == EBinSwiCertStore)
+ {
+ container = &aSwiCertStoreContainer;
+ humanReadable = false;
+ }
+ if(fileType == EHumanSwiCertStore)
+ {
+ container = &aSwiCertStoreContainer;
+ humanReadable = true;
+ }
+
+ if(container == 0)
+ {
+ // failed to decode the output file type!
+ FatalError();
+ }
+ //
+ // Write the container out
+ //
+ writeContainer(aOutputFiles[fileIndex].c_str(), humanReadable, aPemOut, aVerbose, *container);
+ }
+ return;
+}
+
+
+
+/**
+ ValidateLabel
+
+ This function maintains a map of certificate labels to input file
+ (ie file index) and definition.
+
+ If the label is NOT already defined in the map, then the function
+ returns true, which instructs the caller to include the
+ label/certificate in the generated store.
+
+ If the label is already defined in the map, then the function
+ returns false, which instructs the caller to NOT include the
+ label/certificate in the generated store.
+
+ The files on the command line are processed right to left, so if
+ multiple definitions (for the same label) are seen, only the first
+ will be included in the generated store.
+
+ The information saved in the map is used to generate helpful
+ warning/error messages as follows:-
+
+ 1) The saved definition is the first definition encountered, and is
+ therefore the one which has been included in the store.
+
+ 2) The saved file index is the index of the LAST file processed
+ containing a definition for this label. This may be different to
+ the one containing the first definition.
+
+ Consider the following sequence:-
+
+ First processed file - Definition for label Fred
+ Second processed file - Another two definitions for label Fred
+
+ When processing the third definition (in the second file), the
+ saved file index will be that of the second file. The code uses
+ this to check if there are multiple definitions within a SINGLE
+ input file, for the same label.
+
+ If the multiple definitions are within a single human readable
+ file, then this is considered a fatal error, otherwise only a
+ warning is generated.
+
+ Duplicate definitions in different files, generate a warning.
+ */
+bool ValidateLabel(FCSLabelMap &aLabelMap,
+ const StringVector &aInputFiles,
+ CertStoreFileType aFileType,
+ TUint32 aFileIndex,
+ const TCertLabel &aCertLabel)
+{
+ std::string nname = stringFromUtf16(aCertLabel);
+ FCSLabelMap::value_type e(nname, aFileIndex);
+ std::pair<FCSLabelMap::iterator,bool> result = aLabelMap.insert(e);
+ if(result.second == true)
+ {
+ // Not a duplicate
+ return true;
+ }
+
+ // Duplicate label entry
+ dbg << Log::Indent() << "DUPLICATE label detected in '" << aInputFiles[aFileIndex] << "'." << Log::Endl();
+ AutoIndent ai(dbg);
+ dbg << Log::Indent() << "Duplicate entry for '" << e.first << "' ignored. Keeping entry from '" << aInputFiles[(*result.first).second] << "'" <<Log::Endl();
+ if((result.first)->second == TUint32(aFileIndex))
+ {
+ dbg << Log::Indent() << "Both entries are in the same file." << Log::Endl();
+ if((aFileType == EHumanFileCertStore) || (aFileType == EHumanSwiCertStore))
+ {
+ dbg << Log::Indent() << "FATAL error - Clash is within a single text configuration file - aborting!" << Log::Endl();
+ FatalError();
+ }
+ return false; // Insert failed, keep earlier def
+ }
+ else
+ {
+ // Update file index for last definition. This is used to
+ // detect if the last two defs were within a single file.
+ (result.first)->second = TUint32(aFileIndex);
+ return false; // Insert failed, keep earlier def
+ }
+ return false;
+}
+
+void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
+ SubjectToSubjectKeyIdMap &aSubjectMap)
+{
+ // Collect subjectName/SubjectKeyId for all certs
+ for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
+ {
+ const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(aCertStoreContainer[entryIndex]);
+ if(entry.Info().CertificateFormat() != EX509Certificate)
+ {
+ continue;
+ }
+
+ std::pair<SubjectToSubjectKeyIdMap::key_type, SubjectToSubjectKeyIdMap::mapped_type> e;
+ e.first = entry.CertSubject();
+ e.second.iDuplicate = false;
+ e.second.iLabel = stringFromUtf16(entry.Label());
+ e.second.iSubjectKeyIdentifier = entry.Info().SubjectKeyId().iHash;
+ std::pair<SubjectToSubjectKeyIdMap::iterator, bool> result = aSubjectMap.insert(e);
+ if(result.second == false)
+ {
+ dbg << Log::Indent() << "WARNING: Certificate '" << e.second.iLabel << "' has a subject name of '" << e.first << "' which clashes with certificate '" << (*result.first).second.iLabel <<"'" << Log::Endl();
+ (*result.first).second.iDuplicate = true;
+ }
+ }
+
+}
+
+
+void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap,
+ EUseCertificateExtension aUseExtension,
+ EncDecContainer &aCertStoreContainer)
+{
+ // Now loop across certs setting the issuer key id.
+ for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
+ {
+ CertStoreEntry &entry = static_cast<CertStoreEntry &>(aCertStoreContainer[entryIndex]);
+ if(entry.Info().CertificateFormat() != EX509Certificate)
+ {
+ continue;
+ }
+ if(!entry.Info().IssuerKeyId().iAutoKey)
+ {
+ continue;
+ }
+
+ std::string certLabel = stringFromUtf16(entry.Label());
+
+ prog << Log::Indent() << "Attempting to auto set IssuerIeyId for '" << certLabel << "'" << Log::Endl();
+
+ AutoIndent ai(prog);
+
+ // Lookup issuer key id in certificate extension and if found use that.
+ //
+ // X509IssuerKeyId will always set the issuerName.
+ // If aIgnoreExtension is false, then it will attempt to read
+ // the AuthorityKeyId extension. If found (and <160bits), it
+ // will write the ID to issuerId and return true.
+ // Otherwise it will return false.
+ // Certificate read errors are fatal.
+ std::string issuerName;
+ TKeyIdentifier issuerId;
+ if(X509IssuerKeyId(aUseExtension,
+ entry.CertData(), entry.Info().CertSize(),
+ issuerName, issuerId))
+ {
+ // There is an authority key id extension so use its value
+ prog << Log::Indent() << "Using value from certificate '" << certLabel << "' extension" << Log::Endl();
+ entry.Info().IssuerKeyId().iHash = issuerId;
+ }
+ else
+ {
+ // No extension so lookup issuerName in the map
+ prog << Log::Indent() << "Looking up issuer '" << issuerName << "' in map" << Log::Endl();
+ SubjectToSubjectKeyIdMap::const_iterator it = aSubjectMap.find(issuerName);
+ if(it == aSubjectMap.end())
+ {
+ prog << Log::Indent() << "Not found - Using empty IssuerKeyId " << Log::Endl();
+ }
+ else
+ {
+ if((*it).second.iDuplicate)
+ {
+ prog << Log::Indent() << "Found - but multiple certs with matching subject name - Using empty IssuerKeyId" << Log::Endl();
+ }
+ else
+ {
+ prog << Log::Indent() << "Found - Using Subject Key of matching cert" << Log::Endl();
+ entry.Info().IssuerKeyId().iHash = (*it).second.iSubjectKeyIdentifier;
+ }
+ }
+ }
+ }
+
+}
+
+
+
+// End of file