os/security/securityanddataprivacytools/securitytools/certapp/certapp.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 static const char * const sVersion = "certapp version 1.1.++";
    20 #include <e32base.h>
    21 #include <f32file.h>
    22 #include <s32file.h>
    23 #include <map>
    24 #include <sys/stat.h>
    25 #include "encdec.h"
    26 #include "certclients.h"
    27 #include "filecertstore.h"
    28 #include "swicertstore.h"
    29 #include "logger.h"
    30 #include "stringconv.h"
    31 #include <errno.h>
    32 #include "appuidmap.h"
    33 #include "openssl_license.h"
    34 #include "utils.h"
    35 
    36 #ifdef __TOOLS2_LINUX__
    37 #include <unistd.h>
    38 #include <stdio.h>
    39 #else
    40 #include <io.h>
    41 #endif // __TOOLS2_LINUX__
    42 
    43 #ifdef __TOOLS2_LINUX__
    44 #define DIR_SEPARATOR "/"
    45 #else
    46 #define DIR_SEPARATOR "\\"
    47 #endif
    48 
    49 enum CertStoreFileType
    50 {
    51 	EBinCertClients,
    52 	EHumanCertClients,
    53 	EBinFileCertStore,
    54 	EHumanFileCertStore,
    55 	EBinSwiCertStore,
    56 	EHumanSwiCertStore
    57 };
    58 
    59 struct AppMapEntry
    60 	{
    61 	TUint32 iUid;
    62 	TUint32 iInputFileIndex;
    63 	};
    64 typedef std::map<std::string, AppMapEntry> AppMap;
    65 
    66 typedef std::map<std::string, TUint32> FCSLabelMap; // maps cert label to inputFileIndex
    67 
    68 typedef std::vector<std::string> StringVector;
    69 typedef std::vector<CertStoreFileType> CertStoreFileTypeVector;
    70 
    71 void ProcessCommandLine(int aArgc, char **aArgv, 
    72 						StringVector &aInputFiles, 
    73 						StringVector &aInputDirs,
    74 						CertStoreFileTypeVector &aInputFileTypes,
    75 						StringVector &aOutputFiles,
    76 						StringVector &aOutputDirs,
    77 						CertStoreFileTypeVector &aOutputFileTypes,
    78 						bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates);
    79 
    80 void ProcessCertClientFiles(const std::string &aBaseDir,
    81 							const StringVector &aInputFiles,
    82 							const StringVector &aInputDirs,
    83 							const CertStoreFileTypeVector &aInputFileTypes,
    84 							bool &aAllowDuplicates,
    85 							EncDecContainer &aCertAppInfoContainer);
    86 
    87 void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
    88 						 const EncDecContainer &aFileCertStoreContainer,
    89 						 const EncDecContainer &aSwiCertStoreContainer,
    90 						 const std::string &aBaseDir,
    91 						 const StringVector &aOutputFiles, 
    92 						 const StringVector &aOutputDirs,
    93 						 const CertStoreFileTypeVector &aOutputFileTypes,
    94 						 bool aVerbose, bool aPemOut);
    95 
    96 bool ValidateLabel(FCSLabelMap &aLabelMap, 
    97 				   const StringVector &aInputFiles, 
    98 				   CertStoreFileType aFileType,
    99 				   TUint32 aFileIndex, 
   100 				   const TCertLabel &aCertLabel);
   101 
   102 
   103 struct SubjectToSubjectKeyIdEntry
   104 	{
   105 	bool iDuplicate;
   106 	std::string iLabel;
   107 	TKeyIdentifier iSubjectKeyIdentifier;
   108 	};
   109 typedef std::map<std::string, SubjectToSubjectKeyIdEntry> SubjectToSubjectKeyIdMap;
   110 void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
   111 								   SubjectToSubjectKeyIdMap &aSubjectMap);
   112 
   113 void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap, 
   114 					EUseCertificateExtension aUseExtension,
   115 					EncDecContainer &aCertStoreContainer);
   116 
   117 static const std::string OPT_PROGRESS("--progress=");
   118 static const std::string OPT_ERRORS("--errors=");
   119 static const std::string OPT_VERBOSE("--verbose");
   120 static const std::string OPT_ALLOWDUPLICATES("--allowduplicates");
   121 static const std::string OPT_CHDIR("--chdir=");
   122 static const std::string OPT_HCERTCLIENTS_L("--hcertclients=");
   123 static const std::string OPT_HCERTCLIENTS_S("--hcc=");
   124 static const std::string OPT_BCERTCLIENTS_L("--bcertclients=");
   125 static const std::string OPT_BCERTCLIENTS_S("--bcc=");
   126 static const std::string OPT_HFILECERTSTORE_L("--hfilecertstore=");
   127 static const std::string OPT_HFILECERTSTORE_S("--hca=");
   128 static const std::string OPT_BFILECERTSTORE_L("--bfilecertstore=");
   129 static const std::string OPT_BFILECERTSTORE_S("--bca=");
   130 static const std::string OPT_HSWICERTSTORE_L("--hswicertstore=");
   131 static const std::string OPT_HSWICERTSTORE_S("--hswi=");
   132 static const std::string OPT_BSWICERTSTORE_L("--bswicertstore=");
   133 static const std::string OPT_BSWICERTSTORE_S("--bswi=");
   134 
   135 
   136 
   137 void usage()
   138 {
   139 	prog << "certapp: general_options file_options --out file_options" << Log::Endl();
   140 	prog << Log::Endl();
   141 	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();
   142 	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();
   143 	prog << Log::Endl();
   144 	prog << "general_options contains one or more of the following options:-" << Log::Endl();
   145 	prog << "\t--help|-h\tDisplay this usage message" << Log::Endl();
   146 	prog << "\t" << OPT_PROGRESS << "filename\tSave progress output to specified file" << Log::Endl();
   147 	prog << "\t" << OPT_ERRORS << "filename\tSave error output to specified file" << Log::Endl();
   148 	prog << "\t" << OPT_VERBOSE << "Include additional debug comments in output files" << Log::Endl();
   149 	prog << "\t--license Display license information" << Log::Endl();
   150 	prog << "\t--pemout Output certificates in PEM format (nb. format is auto-detected when reading)" << Log::Endl();
   151 	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();
   152 	prog << "An errors/progress filename of - will write to the standard output." << Log::Endl();
   153 	prog << "If the errors/progress filenames are identical, the output will be merged." << Log::Endl();
   154 	prog << Log::Endl();
   155 	prog << "Both instances of file_options contains one or more of the following options:-" << Log::Endl();
   156 	prog << "\t" << OPT_HCERTCLIENTS_L << "|" << OPT_HCERTCLIENTS_S << "filename\t\tHuman readable certclients file" << Log::Endl();
   157 	prog << "\t" << OPT_BCERTCLIENTS_L << "|" << OPT_BCERTCLIENTS_S << "filename\t\tBinary certclients file" << Log::Endl();
   158 	prog << Log::Endl();
   159 	prog << "\t" << OPT_HFILECERTSTORE_L << "|" << OPT_HFILECERTSTORE_S << "filename\tHuman readable filecertstore" << Log::Endl();
   160 	prog << "\t" << OPT_BFILECERTSTORE_L << "|" << OPT_BFILECERTSTORE_S << "filename\tBinary filecertstore" << Log::Endl();
   161 	prog << Log::Endl();
   162 	prog << "\t" << OPT_HSWICERTSTORE_L << "|" << OPT_HSWICERTSTORE_S << "filename\tHuman readable swicertstore" << Log::Endl();
   163 	prog << "\t" << OPT_BSWICERTSTORE_L << "|" << OPT_BSWICERTSTORE_S << "filename\tBinary swicertstore" << Log::Endl();
   164 	prog << Log::Endl();
   165 	prog << "\t" << "--out Change to specifying output files" << Log::Endl();
   166 	prog << "\t" << "--in Change to specifying input files" << Log::Endl();
   167 	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();	
   168 	prog << Log::Endl();
   169 	
   170 	prog << "Examples" << Log::Endl();
   171 	prog << "Read/dump a swicertstore" << Log::Endl();
   172 	prog << "\tcertapp --bcertclients=certclients.dat --bswicertstore=swicertstore.dat --out --hswicertstore=swicertstore.txt" << Log::Endl();
   173 	prog << "Read/dump a filecertstore" << Log::Endl();
   174 	prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --out --hfilecertstore=cacerts.txt" << Log::Endl();
   175 	prog << "Augment a filecertstore" << Log::Endl();
   176 	prog << "\tcertapp --bcertclients=certclients.dat --bfilecertstore=cacerts.dat --hfilecertstore=cacerts_extras.txt --out --bfilecertstore=cacerts_new.dat" << Log::Endl();
   177 	prog << Log::Endl();
   178 	prog << "Device file locations" << Log::Endl();
   179 	prog << "ROM swicertstore - z:\\resource\\swicertstore.dat" << Log::Endl();
   180 	prog << "Writable swicertstore - !:\\resource\\swicertstore\\dat\\* where ! is the system drive" << Log::Endl();
   181 	prog << "Initial filecertstore and certclients z:\\private\\101f72a6\\cacerts.dat and certclients.dat. Copied to sys drive on first use." << Log::Endl();
   182 	prog << "Filecertstore !:\\private\\101f72a6\\cacerts.dat and certclients.dat. where ! is the system drive." << Log::Endl();
   183 }
   184 
   185 void ChangeDir(const std::string &aBaseDir, const std::string &aRelativeDir)
   186 {
   187 	std::string dir(aBaseDir);
   188 	if(aRelativeDir != ".")
   189 		{
   190 		// Build dir to create and change into
   191 		dir.append(DIR_SEPARATOR);
   192 		dir.append(aRelativeDir);
   193 		}
   194 		
   195 	prog << Log::Indent() << "Setting dir to " << dir << Log::Endl();
   196 #ifdef __LINUX__
   197 	(void) mkdir(dir.c_str(),0755); // May already exist so no need to check return code
   198 #else
   199 	(void) mkdir(dir.c_str()); // May already exist so no need to check return code
   200 #endif
   201 	if(chdir(dir.c_str()) < 0)
   202 		{
   203 		dbg << Log::Indent() << "failed to change dir to " << dir << Log::Endl();
   204 		FatalError();
   205 		}
   206 	return;
   207 }
   208 
   209 int main(int argc, char **argv)
   210 {
   211 	dbg.SetStream(&std::cout);
   212 	prog.SetStream(&std::cout);
   213 
   214 	try{
   215 	if(argc==1)
   216 		{
   217 		prog << sVersion << " Use -h for help." << Log::Endl();
   218 		}
   219 
   220 	StringVector inputFiles;
   221 	StringVector inputDirs;
   222 	CertStoreFileTypeVector inputFileTypes;
   223 
   224 	StringVector outputFiles;
   225 	StringVector outputDirs;
   226 	CertStoreFileTypeVector outputFileTypes;
   227 
   228 
   229 	bool verbose = false;
   230 	bool pemOut = false;
   231 	bool allowDuplicates = false;
   232 
   233 	// Process all the command line options and file arguments
   234 	ProcessCommandLine(argc, argv, 
   235 					   inputFiles, inputDirs, inputFileTypes,
   236 					   outputFiles, outputDirs, outputFileTypes,
   237 					   verbose, pemOut, allowDuplicates);
   238 
   239 
   240 	// Save current directory
   241 	std::string baseDir;
   242 	{
   243 	char tmp[FILENAME_MAX];
   244 	if(getcwd(tmp, FILENAME_MAX) == 0)
   245 		{
   246 		dbg << Log::Indent() << "Failed to read current dir" << Log::Endl();
   247 		FatalError();
   248 		}
   249 	baseDir = tmp;
   250 	}
   251 	
   252 
   253 	//
   254 	// Process input files starting with certclient files and working from right to left
   255 	//
   256 	EncDecContainer certAppInfoContainer("ClientInfo", CertificateAppInfo::Factory);
   257 	ProcessCertClientFiles(baseDir, inputFiles, inputDirs, inputFileTypes, 
   258 						   allowDuplicates,
   259 						   certAppInfoContainer);
   260 	
   261 	
   262 	// Generate config data for application uid EncDecEnum object in AppUidListEntry
   263 	AppUidMap::GenerateEnumEntries();
   264 
   265 	//
   266 	// Process remaining input files working from right to left
   267 	//
   268 	EncDecContainer fileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
   269 	FCSLabelMap fcsLabels;
   270 	EncDecContainer swiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
   271 	FCSLabelMap swiLabels;
   272 	for(int fileIndex = inputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
   273 		{
   274 		CertStoreFileType fileType = inputFileTypes[fileIndex];
   275 		if((fileType == EBinFileCertStore) || (fileType == EHumanFileCertStore))
   276 			{
   277 			// Change to correct directory
   278 			ChangeDir(baseDir, inputDirs[fileIndex]);
   279 
   280 			EncDecContainer tmpFileCertStoreContainer("CertStoreEntries", CertStoreEntry::Factory);
   281 			if(fileType == EBinFileCertStore)
   282 				{
   283 				prog << "Reading binary filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
   284 				AutoIndent ai(prog);
   285 				readContainer(inputFiles[fileIndex], false, tmpFileCertStoreContainer);
   286 				}
   287 			if(fileType == EHumanFileCertStore)
   288 				{
   289 				prog << "Reading human filecertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
   290 				AutoIndent ai(prog);
   291 				readContainer(inputFiles[fileIndex], true, tmpFileCertStoreContainer);
   292 				}
   293 			
   294 			// Now merge the new file into the running store.
   295 			prog << Log::Indent() << "Merging filecertstore data" << Log::Endl();
   296 			AutoIndent ai(prog);
   297 			for(TUint32 entryIndex = 0; entryIndex < tmpFileCertStoreContainer.size(); ++entryIndex)
   298 				{
   299 				const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(tmpFileCertStoreContainer[entryIndex]);
   300 				std::string nname = stringFromUtf16(entry.Label());
   301 
   302 				if(!ValidateLabel(fcsLabels, inputFiles, fileType, fileIndex, entry.Label()))
   303 					{
   304 					// Duplicate detected
   305 					if(!allowDuplicates || (fileType == EBinFileCertStore))
   306 						{
   307 						continue; // Skip adding duplicate
   308 						}
   309 					// Only allow duplicates if debugging and reading
   310 					// human readable config file.
   311 					dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
   312 					}
   313 				
   314 				// Add entry
   315 				CertStoreEntry *newEntry = new CertStoreEntry;
   316 				*newEntry = entry;
   317 				fileCertStoreContainer.push_back(newEntry);
   318 				}
   319 			continue;
   320 			}
   321 		
   322 
   323 		if((fileType == EBinSwiCertStore) || (fileType == EHumanSwiCertStore))
   324 			{
   325 			// Change to correct directory
   326 			ChangeDir(baseDir, inputDirs[fileIndex]);
   327 
   328 			EncDecContainer tmpSwiCertStoreContainer("SwiCertStoreEntries", SwiCertStoreEntry::Factory);
   329 			if(fileType == EBinSwiCertStore)
   330 				{
   331 				prog << "Reading binary swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
   332 				AutoIndent ai(prog);
   333 				readContainer(inputFiles[fileIndex], false, tmpSwiCertStoreContainer);
   334 				}
   335 			if(fileType == EHumanSwiCertStore)
   336 				{
   337 				prog << "Reading human swicertstore file '" << inputFiles[fileIndex] << "'" << Log::Endl();
   338 				AutoIndent ai(prog);
   339 				readContainer(inputFiles[fileIndex], true, tmpSwiCertStoreContainer);
   340 				}
   341 
   342 			// Now merge the new file into the running store.
   343 			prog << Log::Indent() << "Merging swicerstore data" << Log::Endl();
   344 			AutoIndent ai(prog);
   345 			for(TUint32 entryIndex = 0; entryIndex < tmpSwiCertStoreContainer.size(); ++entryIndex)
   346 				{
   347 				const SwiCertStoreEntry &entry = static_cast<const SwiCertStoreEntry &>(tmpSwiCertStoreContainer[entryIndex]);
   348 				std::string nname = stringFromUtf16(entry.Label());
   349 		
   350 				if(!ValidateLabel(swiLabels, inputFiles, fileType, fileIndex, entry.Label()))
   351 					{
   352 					// Duplicate detected
   353 					if(!allowDuplicates || (fileType == EBinSwiCertStore))
   354 						{
   355 						continue; // Skip adding duplicate
   356 						}
   357 					// Only allow duplicates if debugging and reading
   358 					// human readable config file.
   359 					dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
   360 					}
   361 				
   362 				// Add entry
   363 				SwiCertStoreEntry *newEntry = new SwiCertStoreEntry;
   364 				*newEntry = entry;
   365 				swiCertStoreContainer.push_back(newEntry);
   366 				}
   367 			continue;
   368 			}
   369 		}
   370 
   371 	// Fix Certificate IDs in fileCertStoreContainer
   372 	for(TUint32 entryIndex=0; entryIndex < fileCertStoreContainer.size(); ++entryIndex)
   373 		{
   374 		CertStoreEntry &entry = static_cast<CertStoreEntry &>(fileCertStoreContainer[entryIndex]);
   375 		entry.Info().SetOutputCertificateId(entryIndex);
   376 		}
   377 	
   378 	// Fix Certificate IDs in swicertstore container.
   379 	for(TUint32 entryIndex=0; entryIndex < swiCertStoreContainer.size(); ++entryIndex)
   380 		{
   381 		SwiCertStoreEntry &entry = static_cast<SwiCertStoreEntry &>(swiCertStoreContainer[entryIndex]);
   382 		entry.Info().SetOutputCertificateId(entryIndex);
   383 		}
   384 
   385 	//
   386 	// Fix auto IssuerKeyId values
   387 	//
   388 	SubjectToSubjectKeyIdMap subjectMap;
   389 	//
   390 	// Fix IssuerKeyId values in swiCertStoreContainer
   391 	//
   392 	// We do not use the AuthorityKeyId extension and only consider
   393 	// certificates in swi certstores.
   394 	//
   395 	// First map all the SWI certificate subject names to SubjectKeyId values
   396 	BuildSubjectToSubjectKeyIdMap(swiCertStoreContainer, subjectMap);
   397 	// Now update IssuerKeyId fields which are set to auto.
   398 	// The AuthorityKeyId extension value will be ignored.
   399 	// The SubjectKeyId of a matching certificate (if there is a
   400 	// single match on issuer name) in the swi cert store will be
   401 	// used.
   402 	SetIssuerKeyId(subjectMap, KIgnoreCertificateExtension, swiCertStoreContainer);
   403 
   404 
   405 	//
   406 	// Fix IssuerKeyId values in fileCertStoreContainer
   407 	//
   408 	// Add all filecertstore certificates to the
   409 	// subjectName/SubjectKeyId map
   410 	BuildSubjectToSubjectKeyIdMap(fileCertStoreContainer, subjectMap);
   411 	// Now update IssuerKeyId fields which are set to auto.  If an the
   412 	// AuthorityKeyId extension is present and <160bits use it,
   413 	// otherwise use the SubjectKeyId of the matching certificate (if
   414 	// there is a single match on issuer name).
   415 	SetIssuerKeyId(subjectMap, KUseCertificateExtension, fileCertStoreContainer);
   416 
   417 	//
   418 	// Now generate output files
   419 	//
   420 	GenerateOutputFiles(certAppInfoContainer, fileCertStoreContainer, swiCertStoreContainer,
   421 						baseDir, outputFiles, outputDirs, outputFileTypes, verbose, pemOut);
   422 	
   423 
   424 	}
   425 	catch(...)
   426 		{
   427 		dbg << Log::Indent() << "C++ expection!" << Log::Endl();
   428 		FatalError();
   429 		}
   430 	
   431 	prog << Log::Indent() << "Normal exit" << Log::Endl();
   432 	prog.Stream().flush();
   433 	dbg.Stream().flush();
   434 	return 0; // All ok
   435 }
   436 
   437 /**
   438    ProcessCommandLine
   439 */
   440 void ProcessCommandLine(int aArgc, char **aArgv, 
   441 						StringVector &aInputFiles, StringVector &aInputDirs, CertStoreFileTypeVector &aInputFileTypes,
   442 						StringVector &aOutputFiles, StringVector &aOutputDirs, CertStoreFileTypeVector &aOutputFileTypes,
   443 						bool &aVerbose, bool &aPemOut, bool &aAllowDuplicates)
   444 {
   445 	std::string progressFile("-");
   446 	static std::fstream sProgressStream;
   447 
   448 	std::string dbgFile("-");
   449 	static std::fstream sDbgStream;
   450 
   451 	StringVector *files = &aInputFiles;
   452 	StringVector *dirs = &aInputDirs;
   453 	CertStoreFileTypeVector *fileTypes = &aInputFileTypes;
   454 
   455 	int argIndex=1;
   456 	// Process overall arguments (-h --progress --errors)
   457 	for(; argIndex < aArgc; ++argIndex)
   458 		{
   459 		std::string arg(aArgv[argIndex]);
   460 
   461 		if(arg == "--license")
   462 			{
   463 			prog << sVersion << Log::Endl();
   464 			prog << "Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies)." << Log::Endl();
   465 			prog << "All rights reserved." << Log::Endl();
   466 			prog << "This component and the accompanying materials are made available" << Log::Endl();
   467 			prog << "under the terms of the License \"Eclipse Public License v1.0\"" << Log::Endl();
   468 			prog << "which accompanies this distribution, and is available" << Log::Endl();
   469 			prog << "at the URL \"http://www.eclipse.org/legal/epl-v10.html\"." << Log::Endl();
   470 			prog << "Initial Contributors:" << Log::Endl();
   471 			prog << "Nokia Corporation - initial contribution." << Log::Endl() << Log::Endl();
   472 			
   473 			prog << "Linked against openssl. Credits and license for openssl follow:-" << Log::Endl();
   474 			prog << openssl_license << Log::Endl();
   475 			
   476 			continue;
   477 			}
   478 
   479 		if(arg == OPT_VERBOSE)
   480 			{
   481 			prog << "Enabling additional output file comments" << Log::Endl();
   482 			aVerbose = true;
   483 			
   484 			continue;
   485 			}
   486 
   487 		if(arg == "--pemout")
   488 			{
   489 			prog << "Setting output certificate format to PEM" << Log::Endl();
   490 			aPemOut = true;
   491 			
   492 			continue;
   493 			}
   494 
   495 		if(arg == OPT_ALLOWDUPLICATES)
   496 			{
   497 			prog << "Allowing addition of duplicate labels in stores and UIDs in certclients when reading human readable input (testing ONLY)" << Log::Endl();
   498 			aAllowDuplicates = true;
   499 			
   500 			continue;
   501 			}
   502 
   503 		if((arg.find(OPT_PROGRESS) == 0) ||
   504 		   (arg.find(OPT_ERRORS) == 0))
   505 			{
   506 			// The following logic is required so that if both streams
   507 			// are set to the same destination we share a streams
   508 			// object and hence avoid buffering issues.
   509 			std::string *thisFile;
   510 			std::fstream *thisStream;
   511 			Log *thisLog;
   512 			std::string *otherFile;
   513 			std::fstream *otherStream;
   514 			Log *otherLog;
   515 
   516 			if(arg.find(OPT_PROGRESS) == 0)
   517 				{
   518 				thisFile = &progressFile;
   519 				thisStream = &sProgressStream;
   520 				thisLog = &prog;
   521 				otherFile = &dbgFile;
   522 				otherStream = &sDbgStream;
   523 				otherLog = &dbg;
   524 
   525 				*thisFile = arg.substr(OPT_PROGRESS.size(), arg.npos);
   526 				}
   527 			else
   528 				{
   529 				thisFile = &dbgFile;
   530 				thisStream = &sDbgStream;
   531 				thisLog = &dbg;
   532 				otherFile = &progressFile;
   533 				otherStream = &sProgressStream;
   534 				otherLog = &prog;
   535 
   536 				*thisFile = arg.substr(OPT_ERRORS.size(), arg.npos);
   537 				}
   538 
   539 			if(*thisFile == *otherFile)
   540 				{
   541 				// Reuse existing stream. This avoids two streams opening the same file...
   542 				thisLog->SetStream(&otherLog->Stream());
   543 				continue;
   544 				}
   545 
   546 			// Need to open a new stream
   547 			if(thisStream->is_open()) thisStream->close();
   548 			if(*thisFile == "-")
   549 				{
   550 				thisLog->SetStream(&std::cout);
   551 				continue;
   552 				}
   553 			
   554 			OpenUtf8FStreamForWrite(*thisStream, thisFile->c_str());
   555 			if(thisStream->fail())
   556 				{
   557 				if(thisLog == &dbg)
   558 					{
   559 					dbg.SetStream(&std::cout);
   560 					}
   561 				dbg << Log::Indent() << "Failed to open log file specified by " << aArgv[argIndex-1] << " '" << *thisFile << "'" << Log::Endl();
   562 				return;
   563 				}
   564 			thisLog->SetStream(thisStream);
   565 			continue;
   566 			}
   567 
   568 		if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
   569 			{
   570 			usage();
   571 			continue;
   572 			}
   573 
   574 		// Not a general option, probably an input file...
   575 		break;
   576 		}
   577 	
   578 	// Process main arguments
   579 	for(; argIndex < aArgc; ++argIndex)
   580 		{
   581 		std::string arg(aArgv[argIndex]);
   582 
   583 		bool gotFile = false;
   584 		if((strcmp(aArgv[argIndex], "--help") == 0) || (strcmp(aArgv[argIndex], "-h") == 0))
   585 			{
   586 			usage();
   587 			continue;
   588 			}
   589 		
   590 		if(arg.find(OPT_CHDIR) == 0)
   591 			{
   592 			dirs->push_back(arg.substr(OPT_CHDIR.size(), arg.npos));
   593 			// Move to next option
   594 			++argIndex;
   595 			if(argIndex >= aArgc) break;
   596 			arg = aArgv[argIndex];
   597 			}
   598 		else
   599 			{
   600 			dirs->push_back(".");
   601 			}
   602 
   603 		std::string fileArg;
   604 		if(arg.find(OPT_BCERTCLIENTS_L) == 0)
   605 			{
   606 			fileTypes->push_back(EBinCertClients);
   607 			fileArg = arg.substr(OPT_BCERTCLIENTS_L.size(), arg.npos);
   608 			gotFile = true;
   609 			}
   610 		if(arg.find(OPT_BCERTCLIENTS_S) == 0)
   611 			{
   612 			fileTypes->push_back(EBinCertClients);
   613 			fileArg = arg.substr(OPT_BCERTCLIENTS_S.size(), arg.npos);
   614 			gotFile = true;
   615 			}
   616 		if(arg.find(OPT_HCERTCLIENTS_L) == 0)
   617 			{
   618 			fileTypes->push_back(EHumanCertClients);
   619 			fileArg = arg.substr(OPT_HCERTCLIENTS_L.size(), arg.npos);
   620 			gotFile = true;
   621 			}
   622 		if(arg.find(OPT_HCERTCLIENTS_S) == 0)
   623 			{
   624 			fileTypes->push_back(EHumanCertClients);
   625 			fileArg = arg.substr(OPT_HCERTCLIENTS_S.size(), arg.npos);
   626 			gotFile = true;
   627 			}
   628 		if(arg.find(OPT_BFILECERTSTORE_L) == 0)
   629 			{
   630 			fileTypes->push_back(EBinFileCertStore);
   631 			fileArg = arg.substr(OPT_BFILECERTSTORE_L.size(), arg.npos);
   632 			gotFile = true;
   633 			}
   634 		if(arg.find(OPT_BFILECERTSTORE_S) == 0)
   635 			{
   636 			fileTypes->push_back(EBinFileCertStore);
   637 			fileArg = arg.substr(OPT_BFILECERTSTORE_S.size(), arg.npos);
   638 			gotFile = true;
   639 			}
   640 		if(arg.find(OPT_HFILECERTSTORE_L) == 0)
   641 			{
   642 			fileTypes->push_back(EHumanFileCertStore);
   643 			fileArg = arg.substr(OPT_HFILECERTSTORE_L.size(), arg.npos);
   644 			gotFile = true;
   645 			}
   646 		if(arg.find(OPT_HFILECERTSTORE_S) == 0)
   647 			{
   648 			fileTypes->push_back(EHumanFileCertStore);
   649 			fileArg = arg.substr(OPT_HFILECERTSTORE_S.size(), arg.npos);
   650 			gotFile = true;
   651 			}
   652 		if(arg.find(OPT_BSWICERTSTORE_L) == 0)
   653 			{
   654 			fileTypes->push_back(EBinSwiCertStore);
   655 			fileArg = arg.substr(OPT_BSWICERTSTORE_L.size(), arg.npos);
   656 			gotFile = true;
   657 			}
   658 		if(arg.find(OPT_BSWICERTSTORE_S) == 0)
   659 			{
   660 			fileTypes->push_back(EBinSwiCertStore);
   661 			fileArg = arg.substr(OPT_BSWICERTSTORE_S.size(), arg.npos);
   662 			gotFile = true;
   663 			}
   664 		if(arg.find(OPT_HSWICERTSTORE_L) == 0)
   665 			{
   666 			fileTypes->push_back(EHumanSwiCertStore);
   667 			fileArg = arg.substr(OPT_HSWICERTSTORE_L.size(), arg.npos);
   668 			gotFile = true;
   669 			}
   670 		if(arg.find(OPT_HSWICERTSTORE_S) == 0)
   671 			{
   672 			fileTypes->push_back(EHumanSwiCertStore);
   673 			fileArg = arg.substr(OPT_HSWICERTSTORE_S.size(), arg.npos);
   674 			gotFile = true;
   675 			}
   676 
   677 		if(arg.find("--out") == 0)
   678 			{
   679 			files = &aOutputFiles;
   680 			dirs = &aOutputDirs;
   681 			fileTypes = &aOutputFileTypes;
   682 			continue;
   683 			}
   684 
   685 		if(arg.find("--in") == 0)
   686 			{
   687 			files = &aInputFiles;
   688 			dirs = &aInputDirs;
   689 			fileTypes = &aInputFileTypes;
   690 			continue;
   691 			}
   692 
   693 		if(gotFile)
   694 			{
   695 			files->push_back(fileArg);
   696 			continue;
   697 			}
   698 		
   699 		usage();
   700 		dbg << Log::Indent() << "Unknown option " << (const char *) aArgv[argIndex] << Log::Endl();
   701 		FatalError();
   702 		}
   703 	return;
   704 }
   705 
   706 void ProcessCertClientFiles(const std::string &aBaseDir,
   707 							const StringVector &aInputFiles,
   708 							const StringVector &aInputDirs,
   709 							const CertStoreFileTypeVector &aInputFileTypes,
   710 							bool &aAllowDuplicates,
   711 							EncDecContainer &aCertAppInfoContainer)
   712 {
   713 	AppMap appMap;
   714 	for(int fileIndex = aInputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
   715 		{
   716 		CertStoreFileType fileType = aInputFileTypes[fileIndex];
   717 		if((fileType != EBinCertClients) && (fileType != EHumanCertClients))
   718 			{
   719 			continue;
   720 			}
   721 		
   722 		// Change to correct directory
   723 		ChangeDir(aBaseDir, aInputDirs[fileIndex]);
   724 
   725 		EncDecContainer tmpCertInfoContainer("ClientInfo", CertificateAppInfo::Factory);
   726 
   727 		if(fileType == EBinCertClients)
   728 			{
   729 			prog << Log::Indent() << "Reading binary certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
   730 			AutoIndent ai(prog);
   731 			readContainer(aInputFiles[fileIndex], false, tmpCertInfoContainer);
   732 			}
   733 		else
   734 			{
   735 			prog << Log::Indent() << "Reading human certclients file '" << aInputFiles[fileIndex] << "'" << Log::Endl();
   736 			AutoIndent ai(prog);
   737 			readContainer(aInputFiles[fileIndex], true, tmpCertInfoContainer);
   738 			}
   739 
   740 		// Now merge the new file into the running store.
   741 		prog << Log::Indent() << "Merging certclients data" << Log::Endl();
   742 		AutoIndent ai(prog);
   743 		AutoIndent ai2(dbg);
   744 		for(TUint32 entryIndex = 0; entryIndex < tmpCertInfoContainer.size(); ++entryIndex)
   745 			{
   746 			const CertificateAppInfo &info = static_cast<const CertificateAppInfo &>(tmpCertInfoContainer[entryIndex]);
   747 			std::string nname = stringFromUtf16(info.Name());
   748 			//prog << Log::Indent() << "checking " << nname << Log::Endl();
   749 
   750 
   751 			TInt32 lastIndex;
   752 			std::string firstDef;
   753 			if(!AppUidMap::InsertUidDefinition(info.Id().iUid, nname, fileIndex,
   754 											   lastIndex, firstDef))
   755 				{
   756 				// Duplicate entry for UID
   757 				if(nname == firstDef)
   758 					{
   759 					// But both entries have the same value
   760 					prog << Log::Indent() << "Duplicate, but identical, entries for UID 0x" << info.Id().iUid << " '" << nname << "'." << Log::Endl();
   761 					AutoIndent ai(prog);
   762 					prog << Log::Indent() << "From files '" << aInputFiles[lastIndex] << "' and '" << aInputFiles[fileIndex] << "'." << Log::Endl();
   763 					}
   764 				else
   765 					{
   766 					// Entries have different values
   767 					dbg << Log::Indent() << "DUPLICATE entry for UID 0x" << info.Id().iUid << Log::Endl();
   768 					AutoIndent ai(dbg);
   769 					dbg << Log::Indent() << "Ignoring '" << nname << "' from '"  << aInputFiles[fileIndex] << "'." << Log::Endl();
   770 					dbg << Log::Indent() << "Keeping '" << firstDef << "' from '" << aInputFiles[lastIndex] << "'." << Log::Endl();
   771 					if(lastIndex == fileIndex)
   772 						{
   773 						if(fileType == EBinCertClients)
   774 							{
   775 							dbg << Log::Indent() << "Both entries are in the same binary same file!" << Log::Endl();
   776 							continue; // Skip adding duplicate
   777 							}
   778 						dbg << Log::Indent() << "Clash is within a single text configuration file!" << Log::Endl();
   779 						if(!aAllowDuplicates)
   780 							{
   781 							FatalError();
   782 							}
   783 						}
   784 					}
   785 
   786 				// Only add duplicates when debugging and the add is
   787 				// from a human readable config file.
   788 				if(!aAllowDuplicates || (fileType != EHumanCertClients))
   789 					{
   790 					continue; // Skip adding duplicate
   791 					}
   792 				dbg << Log::Indent() << "Adding anyway due to " << OPT_ALLOWDUPLICATES << Log::Endl();
   793 				}
   794 
   795 			// Add entry
   796 			CertificateAppInfo *newInfo = new CertificateAppInfo;
   797 			*newInfo = info;
   798 			aCertAppInfoContainer.push_back(newInfo);
   799 			}
   800 		}
   801 }
   802 
   803 
   804 
   805 /**
   806    Write output files to disk
   807  */
   808 void GenerateOutputFiles(const EncDecContainer &aCertAppInfoContainer,
   809 						 const EncDecContainer &aFileCertStoreContainer,
   810 						 const EncDecContainer &aSwiCertStoreContainer,
   811 						 const std::string &aBaseDir,
   812 						 const StringVector &aOutputFiles, 
   813 						 const StringVector &aOutputDirs,
   814 						 const CertStoreFileTypeVector &aOutputFileTypes,
   815 						 bool aVerbose, bool aPemOut)
   816 {
   817 	for(int fileIndex = aOutputFiles.size()-1; fileIndex >= 0 ; --fileIndex)
   818 		{
   819 		// Change to correct directory
   820 		ChangeDir(aBaseDir, aOutputDirs[fileIndex]);
   821 		
   822 		CertStoreFileType fileType = aOutputFileTypes[fileIndex];
   823 		//
   824 		// Set the container and write mode to use
   825 		//
   826 		const EncDecContainer *container = 0;
   827 		bool humanReadable = false;
   828 		if(fileType == EBinCertClients)
   829 			{
   830 			container = &aCertAppInfoContainer;
   831 			humanReadable = false;
   832 			}
   833 		if(fileType == EHumanCertClients)
   834 			{
   835 			container = &aCertAppInfoContainer;
   836 			humanReadable = true;
   837 			}
   838 		if(fileType == EBinFileCertStore)
   839 			{
   840 			container = &aFileCertStoreContainer;
   841 			humanReadable = false;
   842 			}
   843 		if(fileType == EHumanFileCertStore)
   844 			{
   845 			container = &aFileCertStoreContainer;
   846 			humanReadable = true;
   847 			}
   848 		if(fileType == EBinSwiCertStore)
   849 			{
   850 			container = &aSwiCertStoreContainer;
   851 			humanReadable = false;
   852 			}
   853 		if(fileType == EHumanSwiCertStore)
   854 			{
   855 			container = &aSwiCertStoreContainer;
   856 			humanReadable = true;
   857 			}
   858 		
   859 		if(container == 0)
   860 			{
   861 			// failed to decode the output file type!
   862 			FatalError();
   863 			}
   864 		//
   865 		// Write the container out
   866 		//
   867 		writeContainer(aOutputFiles[fileIndex].c_str(), humanReadable, aPemOut, aVerbose, *container);
   868 		}
   869 	return;
   870 }
   871 
   872 
   873 
   874 /**
   875    ValidateLabel
   876 
   877    This function maintains a map of certificate labels to input file
   878    (ie file index) and definition.
   879    
   880    If the label is NOT already defined in the map, then the function
   881    returns true, which instructs the caller to include the
   882    label/certificate in the generated store.
   883 
   884    If the label is already defined in the map, then the function
   885    returns false, which instructs the caller to NOT include the
   886    label/certificate in the generated store.
   887 
   888    The files on the command line are processed right to left, so if
   889    multiple definitions (for the same label) are seen, only the first
   890    will be included in the generated store.
   891 
   892    The information saved in the map is used to generate helpful
   893    warning/error messages as follows:-
   894 
   895    1) The saved definition is the first definition encountered, and is
   896    therefore the one which has been included in the store.
   897 
   898    2) The saved file index is the index of the LAST file processed
   899    containing a definition for this label. This may be different to
   900    the one containing the first definition.
   901 
   902    Consider the following sequence:-
   903 
   904    First processed file - Definition for label Fred
   905    Second processed file - Another two definitions for label Fred
   906 
   907    When processing the third definition (in the second file), the
   908    saved file index will be that of the second file. The code uses
   909    this to check if there are multiple definitions within a SINGLE
   910    input file, for the same label.
   911 
   912    If the multiple definitions are within a single human readable
   913    file, then this is considered a fatal error, otherwise only a
   914    warning is generated.
   915 
   916    Duplicate definitions in different files, generate a warning.
   917  */
   918 bool ValidateLabel(FCSLabelMap &aLabelMap, 
   919 				   const StringVector &aInputFiles, 
   920 				   CertStoreFileType aFileType,
   921 				   TUint32 aFileIndex, 
   922 				   const TCertLabel &aCertLabel)
   923 {
   924 	std::string nname = stringFromUtf16(aCertLabel);
   925 	FCSLabelMap::value_type e(nname, aFileIndex);
   926 	std::pair<FCSLabelMap::iterator,bool> result = aLabelMap.insert(e);
   927 	if(result.second == true)
   928 		{
   929 		// Not a duplicate
   930 		return true;
   931 		}
   932 	
   933 	// Duplicate label entry
   934 	dbg << Log::Indent() << "DUPLICATE label detected in '" << aInputFiles[aFileIndex] << "'." << Log::Endl();
   935 	AutoIndent ai(dbg);
   936 	dbg << Log::Indent() << "Duplicate entry for '" << e.first << "' ignored. Keeping entry from '" << aInputFiles[(*result.first).second] << "'" <<Log::Endl();
   937 	if((result.first)->second == TUint32(aFileIndex))
   938 		{
   939 		dbg << Log::Indent() << "Both entries are in the same file." << Log::Endl();
   940 		if((aFileType == EHumanFileCertStore) || (aFileType == EHumanSwiCertStore))
   941 			{
   942 			dbg << Log::Indent() << "FATAL error - Clash is within a single text configuration file - aborting!" << Log::Endl();
   943 			FatalError();
   944 			}
   945 		return false; // Insert failed, keep earlier def
   946 		}
   947 	else
   948 		{
   949 		// Update file index for last definition. This is used to
   950 		// detect if the last two defs were within a single file.
   951 		(result.first)->second = TUint32(aFileIndex);
   952 		return false; // Insert failed, keep earlier def
   953 		}
   954 	return false;
   955 }
   956 
   957 void BuildSubjectToSubjectKeyIdMap(const EncDecContainer &aCertStoreContainer,
   958 								   SubjectToSubjectKeyIdMap &aSubjectMap)
   959 {
   960 	// Collect subjectName/SubjectKeyId for all certs
   961 	for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
   962 		{
   963 		const CertStoreEntry &entry = static_cast<const CertStoreEntry &>(aCertStoreContainer[entryIndex]);
   964 		if(entry.Info().CertificateFormat() !=  EX509Certificate)
   965 			{
   966 			continue;
   967 			}
   968 
   969 		std::pair<SubjectToSubjectKeyIdMap::key_type, SubjectToSubjectKeyIdMap::mapped_type> e;
   970 		e.first = entry.CertSubject();
   971 		e.second.iDuplicate = false;
   972 		e.second.iLabel = stringFromUtf16(entry.Label());
   973 		e.second.iSubjectKeyIdentifier =  entry.Info().SubjectKeyId().iHash;
   974 		std::pair<SubjectToSubjectKeyIdMap::iterator, bool> result = aSubjectMap.insert(e);
   975 		if(result.second == false)
   976 			{
   977 			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();
   978 			(*result.first).second.iDuplicate = true;
   979 			}
   980 		}
   981 	
   982 }
   983 
   984 
   985 void SetIssuerKeyId(SubjectToSubjectKeyIdMap &aSubjectMap,
   986 					EUseCertificateExtension aUseExtension,
   987 					EncDecContainer &aCertStoreContainer)
   988 {
   989 	// Now loop across certs setting the issuer key id.
   990 	for(TUint32 entryIndex=0; entryIndex < aCertStoreContainer.size(); ++entryIndex)
   991 		{
   992 		CertStoreEntry &entry = static_cast<CertStoreEntry &>(aCertStoreContainer[entryIndex]);
   993 		if(entry.Info().CertificateFormat() !=  EX509Certificate)
   994 			{
   995 			continue;
   996 			}
   997 		if(!entry.Info().IssuerKeyId().iAutoKey)
   998 			{
   999 			continue;
  1000 			}
  1001 
  1002 		std::string certLabel = stringFromUtf16(entry.Label());
  1003 		
  1004 		prog << Log::Indent() << "Attempting to auto set IssuerIeyId for '" << certLabel << "'" << Log::Endl();
  1005 
  1006 		AutoIndent ai(prog);
  1007 
  1008 		// Lookup issuer key id in certificate extension and if found use that.
  1009 		// 
  1010 		// X509IssuerKeyId will always set the issuerName.
  1011 		// If aIgnoreExtension is false, then it will attempt to read
  1012 		// the AuthorityKeyId extension. If found (and <160bits), it
  1013 		// will write the ID to issuerId and return true.
  1014 		// Otherwise it will return false.
  1015 		// Certificate read errors are fatal.
  1016 		std::string issuerName;
  1017 		TKeyIdentifier issuerId;
  1018 		if(X509IssuerKeyId(aUseExtension,
  1019 						   entry.CertData(), entry.Info().CertSize(),
  1020 						   issuerName, issuerId))
  1021 			{
  1022 			// There is an authority key id extension so use its value
  1023 			prog << Log::Indent() << "Using value from certificate '" << certLabel << "' extension" << Log::Endl();
  1024 			entry.Info().IssuerKeyId().iHash = issuerId;
  1025 			}
  1026 		else
  1027 			{
  1028 			// No extension so lookup issuerName in the map
  1029 			prog << Log::Indent() << "Looking up issuer '" << issuerName << "' in map" << Log::Endl();
  1030 			SubjectToSubjectKeyIdMap::const_iterator it = aSubjectMap.find(issuerName);
  1031 			if(it == aSubjectMap.end())
  1032 				{
  1033 				prog << Log::Indent() << "Not found - Using empty IssuerKeyId " << Log::Endl();
  1034 				}
  1035 			else
  1036 				{
  1037 				if((*it).second.iDuplicate)
  1038 					{
  1039 					prog << Log::Indent() << "Found - but multiple certs with matching subject name - Using empty IssuerKeyId" << Log::Endl();
  1040 					}
  1041 				else
  1042 					{
  1043 					prog << Log::Indent() << "Found - Using Subject Key of matching cert" << Log::Endl();
  1044 					entry.Info().IssuerKeyId().iHash = (*it).second.iSubjectKeyIdentifier;
  1045 					}
  1046 				}
  1047 			}
  1048 		}
  1049 
  1050 }
  1051 
  1052 
  1053 
  1054 // End of file