PKIFPathBuilder2.cpp

Go to the documentation of this file.
00001 
00009 #include "PKIFPathBuilder2.h"
00010 #include "PKIFBasicPathState2.h"
00011 #include "PKIFPathSettings.h"
00012 #include "IPKIFCertRepository.h"
00013 #include "IPKIFCertRepositoryUpdate.h"
00014 #include "IPKIFTrustCache.h"
00015 #include "IPKIFCRLRepository.h"
00016 #include "PKIFMediators.h"
00017 
00018 #include "ToolkitUtils.h"
00019 #include "BuilderUtils.h"
00020 #include "BasicChecksUtils.h"
00021 #include "GottaMatch.h"
00022 #include "BuilderStatistics.h"
00023 
00024 #include "PKIFPathException.h"
00025 #include "PKIFErrors.h"
00026 #include "PKIFCertificateNodeEntry.h"
00027 #include "Name.h"
00028 #include "Certificate.h"
00029 #include "CertificateNodeListWithSourceInfo.h"
00030 #include "PKIFDefaultScoring.h"
00031 #include "PKIFTrustRoot.h"
00032 #include "NodeInNodeList.h"
00033 #include "PKIFCertStatus.h"
00034 #include "PKIFCertificatePath.h"
00035 #include "PKIFPathLogger.h"
00036 #include "PathResults.h"
00037 #include "AuthorityKeyIdentifier.h"
00038 #include <sstream>
00039 
00040 #include <boost/shared_ptr.hpp>
00041 #include "boost/numeric/conversion/cast.hpp"
00042 
00043 using boost::numeric_cast;
00044 using boost::bad_numeric_cast;
00045 
00046 #include <iterator>
00047 
00048 using namespace std;
00049 using namespace boost;
00050 
00051 
00052 extern bool KeyIDsMatch(CPKIFAuthorityKeyIdentifierPtr& akid, const IPKIFTrustAnchorPtr& curCert);
00053 
00054 #ifdef _DEBUG_PATH_DUMP
00055 #include <fstream>
00056 ofstream g_pathLogFile;
00057 #endif
00058 
00064 class KeyIDCompare
00065 {
00066 public:
00074     bool operator()(const IPKIFTrustAnchorPtr& lhsTA, const IPKIFTrustAnchorPtr& rhsTA)
00075     {
00076         int lhsScore = 0, rhsScore = 0;
00077 
00078         CPKIFAuthorityKeyIdentifierPtr akid = m_currentCert->GetExtension<CPKIFAuthorityKeyIdentifier>();
00079 
00080         if(lhsTA)
00081         {
00082             if(KeyIDsMatch(akid, lhsTA))
00083             {
00084                 lhsScore+=5;
00085             }
00086         }
00087         if(rhsTA)
00088         {
00089             if(KeyIDsMatch(akid, rhsTA))
00090             {
00091                 rhsScore+=5;
00092             }
00093         }
00094 
00095         return lhsScore > rhsScore;
00096     }
00104     void SetCurrent(
00106         const CPKIFCertificatePtr& current) {m_currentCert = current;}
00107 private:
00108     CPKIFCertificatePtr m_currentCert;
00109 };
00110 
00112 struct CPKIFPathBuilder2Impl 
00113 {
00114     CPKIFPathBuilder2 *m_parent;
00115 
00116     //function that builds a table or grows a table by extending rows with additional sources
00117     bool BuildOrGrowTable(CPKIFBasicPathState2* basicState, CPKIFPathSettingsPtr& settings, CPKIFCertificatePtr& curCert, CPKIFCertificateNodeList& prevPath);
00118 
00119     //function that actually handles growing rows with additional sources
00120     bool GrowTable(CPKIFBasicPathState2* basicState, IPKIFCertRepository* iCert, 
00121         IPKIFCertRepositoryUpdate* iCertUpdate, IPKIFTrustCache* iTrust, CPKIFPathSettingsPtr& settings);
00122 
00123     //function that checks for paths in the current table of certs
00124     bool CheckAlternatives(CPKIFCertificatePath& path, CPKIFBasicPathState2* basicState);
00125 
00126     //function that removes the current root row from the table
00127     //added roots param and associated processing 12/4/2003
00128     void PuntCurrentRoot(CPKIFBasicPathState2* basicState, IPKIFTrustAnchorList& roots);
00129 
00130     //function that removes the current row nearest the root
00131     bool PuntTopRow(CPKIFBasicPathState2* basicState, CPKIFNamePtr& prevName, 
00132         CPKIFCertificatePtr& curCert, IPKIFCertRepository* iCert, IPKIFCertRepositoryUpdate* iCertUpdate,
00133         IPKIFTrustCache* iTrust, CPKIFPathSettingsPtr& settings);
00134 
00135     //function that removes certs from a list that would create a loop in the current path
00136     void RemoveLoopMakers(CPKIFCertificateNodeList& certList, CPKIFBasicPathState2* basicState, CPKIFCertificateNodeListWithSourceInfoPtr& currPos, bool growingRow = false);
00137 
00138     void SearchForFailure(CPKIFBasicPathState2* basicState, CPKIFCertificateNodeList& prevPath, CPKIFPathSettingsPtr& settings);
00139     bool PuntFailure(CPKIFBasicPathState2* basicState, CPKIFCertificateNodeEntryPtr& ppPos);
00140 
00141     bool GrowRow(CPKIFCertificateNodeListWithSourceInfoPtr& pos, IPKIFCertRepository* iCert, IPKIFCertRepositoryUpdate* iCertUpdate, CPKIFBasicPathState2* basicState, 
00142         CPKIFCertificatePtr& curCert, IPKIFTrustCache* iTrust, CPKIFPathSettingsPtr& settings, CPKIFCertificateNodeListWithSourceInfoPtr& posPlusOne);
00143 };
00145 
00153 CPKIFPathBuilder2::CPKIFPathBuilder2(void)
00154 :m_impl(new CPKIFPathBuilder2Impl)
00155 {
00156     LOG_STRING_DEBUG("CPKIFPathBuilder2::CPKIFPathBuilder2", thisComponent, 0, this);
00157     m_impl->m_parent = this;
00158 }
00166 CPKIFPathBuilder2::~CPKIFPathBuilder2(void)
00167 {
00168     LOG_STRING_DEBUG("CPKIFPathBuilder2::~CPKIFPathBuilder2", thisComponent, 0, this);
00169     
00170     delete m_impl;
00171     m_impl = 0;
00172 }
00180 void CPKIFPathBuilder2::Initialize() 
00181 {
00182     LOG_STRING_DEBUG("CPKIFPathBuilder2::Initialize()", thisComponent, 0, this);
00183 }
00184 
00185 //----------------------------------------------------------------------------------------------------
00186 //
00187 //  Private interface functions
00188 //
00189 //----------------------------------------------------------------------------------------------------
00190 //----------------------------------------------------------------------------------------------------
00191 //  GrowTable (called from BuildOrGrowTable, GrowTable and PuntTopRow)
00192 //      This function tries to expand the existing table by consulting REMOTE sources
00193 //      for rows that were built entirely from LOCAL sources.  After calling this function
00194 //      all rows in the table will have been expanded if possible.  All rows are done at once to 
00195 //      simplify the code in CheckAlternatives that screens for previously returned paths.
00196 //----------------------------------------------------------------------------------------------------
00205 bool CPKIFPathBuilder2Impl::GrowRow(
00207     CPKIFCertificateNodeListWithSourceInfoPtr& pos, 
00209     IPKIFCertRepository* iCert, 
00211     IPKIFCertRepositoryUpdate* iCertUpdate,
00213     CPKIFBasicPathState2* basicState,
00215     CPKIFCertificatePtr& curCert, 
00217     IPKIFTrustCache* iTrust, 
00219     CPKIFPathSettingsPtr& settings,
00221     CPKIFCertificateNodeListWithSourceInfoPtr& posPlusOne)
00222 {
00223     if(LOCAL == pos->m_maxSource)
00224     {
00225         //it may not actually be local because items from the in memory cache
00226         //may actually have been remote during this session.  if this is the case then
00227         //we want to avoid another (unnecessary) REMOTE attempt
00228         CPKIFCertificateNodeListWithSourceInfo::iterator nodeListPos;
00229         CPKIFCertificateNodeListWithSourceInfo::iterator nodeListEnd = pos->end();
00230         for(nodeListPos = pos->begin(); nodeListPos != nodeListEnd; ++nodeListPos)
00231         {
00232             if(LOCAL != (*nodeListPos)->GetSource())
00233                 return false;//bail out now rather than try another REMOTE attempt
00234         }
00235     }
00236 
00237     if(NULL == basicState->m_reserved)
00238         return false;
00239 
00240     CPKIFCertificatePtr frontCert = pos->front()->GetCert();
00241     CPKIFNamePtr curCertSubject = frontCert->Subject();
00242     CPKIFCertificateNodeList certList;
00243 
00244     //added 7/22/2004 to check AIA/IAN
00245     //changed iterator declaration 11/23/2004
00246     //CPKIFCertificateNodeListWithSourceInfo::iterator tPos = posPlusOne->begin();
00247     //CPKIFCertificateNodeListWithSourceInfo::iterator tEnd = posPlusOne->end();
00248     //for(;tPos != tEnd; ++tPos)
00249     //{
00250     //  CPKIFCertificatePtr tCert = (*tPos)->GetCert();
00251     //  GetCertsFromIssuerAltName(*tCert, certList);
00252     //}
00253 
00254     if(posPlusOne)
00255     {
00256         CPKIFCertificateNodeListWithSourceInfo::iterator tPos = posPlusOne->begin();
00257         CPKIFCertificateNodeListWithSourceInfo::iterator tEnd = posPlusOne->end();
00258         for(;tPos != tEnd; ++tPos)
00259         {
00260             CPKIFCertificatePtr tCert = (*tPos)->GetCert();
00261             iCert->GetCertificates(tCert, certList, REMOTE);
00262         }
00263     }
00264 
00265     //the commenting of the following two lines was reversed to avoid using the interface that does not use the syn store when building
00266     //iCert->GetCertificates(curCertSubject, certList, REMOTE);
00267     iCert->GetCertificates(frontCert, certList, REMOTE);
00268 
00269     pos->m_maxSource = REMOTE; //added 8/27/2004
00270     basicState->m_maxSource = ALL;
00271     size_t certListSize = certList.size();
00272     if(0 != certListSize)
00273     {
00274         //remove any certs that would create a loop with certs already in the path
00275         RemoveLoopMakers(certList, basicState, pos, true);
00276         certListSize = certList.size();
00277     }
00278     
00279     if(0 == certListSize)
00280         return false;
00281     else
00282     {
00283         bool retval = false;
00284 
00285         //code in this block is very similar to code in BuildAndGrowTable - if modify here investigate there
00286         CPKIFCertificateNodeList::iterator certListPos;
00287         CPKIFCertificateNodeList::iterator certListEnd = certList.end();
00288         for(certListPos = certList.begin(); certListPos != certListEnd; ++certListPos)
00289         {
00290             //make sure we ignore certs for other folks that may have been in the directory
00291             if(*curCertSubject == *(*certListPos)->GetCert()->Subject())
00292             {
00293                 GottaMatch<CPKIFCertificateNodeEntryPtr> gm;
00294                 gm.SetRHS(*certListPos);
00295                 if(pos->end() == find_if(pos->begin(), pos->end(), gm))
00296                 {
00297                     //if we found certs - add them to the LOCAL cache
00298                     if(iCertUpdate && LOCAL != (*certListPos)->GetSource())
00299                     {
00300                         try
00301                         {
00302                             iCertUpdate->AddCertificate(CA, *certListPos);
00303                         }
00304                         catch(CPKIFException&)
00305                         {
00306                             //delete e;//don't fail because we have no in-memory cache or whatever
00307                         }
00308                     }
00309 
00310                     basicState->m_maxSource = ALL;
00311                     pos->push_back(*certListPos);
00312                     pos->m_maxSource = ALL;
00313                     retval = true;
00314                 }
00315             }//end if curCert subject matches certListPos subject
00316         }//end iteration over certList
00317 
00318         if(retval)
00319         {
00320             //eliminate template and always use the default scoring class
00321             CPKIFDefaultScoring s;
00322 
00323             //Scoring s;    //create an object of the type defined by the template parameter
00324 
00325             //reviewed 4/24 - the path depth is governed by an integer value so size_t should never exceed that value (or even come close)
00326             int size = 0;
00327             try 
00328             {
00329                 size = numeric_cast<int>(basicState->m_table.size());
00330             }
00331             catch(bad_numeric_cast &) 
00332             {
00333                 throw CPKIFException(TOOLKIT_PATH, COMMON_INVALID_INPUT, "Bable size is an impossibly long number.");
00334             }
00335             s.ScoreAndSortNodes(pos, curCert, settings, iTrust, size - 1,iCert);//-1 to not count target cert
00336             retval = pos->size() != 0;
00337         }
00338 
00339         return retval;
00340     }//end else 0 != certListSize
00341 }
00342 
00343 //----------------------------------------------------------------------------------------------------
00344 //  GrowTable (called from BuildOrGrowTable)
00345 //      This function tries to expand the existing table by consulting REMOTE sources
00346 //      for rows that were built entirely from LOCAL sources.  After calling this function
00347 //      all rows in the table will have been expanded if possible.  All rows are done at once to 
00348 //      simplify the code in CheckAlternatives that screens for previously returned paths.
00349 //----------------------------------------------------------------------------------------------------
00360 bool CPKIFPathBuilder2Impl::GrowTable(
00362     CPKIFBasicPathState2* basicState, 
00364     IPKIFCertRepository* iCert,
00366     IPKIFCertRepositoryUpdate* iCertUpdate, 
00368     IPKIFTrustCache* iTrust, 
00370     CPKIFPathSettingsPtr& settings)
00371 {
00372     bool retVal = false;
00373 
00374     CPKIFCertificatePtr curCert;
00375     if(!basicState->m_table.empty())
00376     {
00377         //should always get here
00378         curCert = basicState->m_table.front()->front()->GetCert(); //should be only
00379     }
00380 /*  if(NULL != basicState->m_curRoot)
00381     {
00382         //XXX***TA TEMP WORKAROUND
00383         CPKIFTrustRoot* ta = dynamic_cast<CPKIFTrustRoot*>(&(*(*basicState->m_curRoot)));
00384         if(ta != NULL)
00385             ta->GetCert(curCert);
00386     }
00387     else if(!basicState->m_rootList.empty())
00388     {
00389         //XXX***TA TEMP WORKAROUND
00390         CPKIFTrustRoot* ta = dynamic_cast<CPKIFTrustRoot*>(&(*(basicState->m_rootList.front())));
00391         if(ta != NULL)
00392             ta->GetCert(curCert);
00393     }
00394     else
00395     {
00396         //huh?
00397     }
00398 */
00399 
00400     //probably isn't necessary to use reverse iterators (except when assembling a path for return)
00401     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos = basicState->m_table.rbegin();
00402     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
00403     for(; pos != end; ++pos)
00404     {
00405         //only pursue rows that haven't previously been pursued beyond LOCAL (and that aren't empty)
00406         //never try to grow the target row
00407         if(LOCAL == (*pos)->m_maxSource && !(*pos)->empty() && (pos + 1) != end)
00408         {
00409             if(GrowRow(*pos, iCert, iCertUpdate, basicState, curCert, iTrust, settings, *(pos + 1)))
00410             {
00411                 retVal = true;
00412                 if(basicState->m_table.rbegin() == pos)
00413                 {
00414                     basicState->m_curRoot = NULL;
00415                 }
00416             }
00417         }//end LOCAL == maxSource
00418 
00419         if(0 == (*pos)->size())
00420             return false;
00421         else
00422             curCert = (*pos)->front()->GetCert();
00423     }//end table iteration
00424 
00425     return retVal;
00426 }
00427 
00428 //----------------------------------------------------------------------------------------------------
00429 //  PuntCurrentRoot (called from BuildOrGrowTable)
00430 //      This function simply empties the root list forcing a subsequent BuildOrGrowTable activity
00431 //      to build to a new root.
00432 //----------------------------------------------------------------------------------------------------
00440 void CPKIFPathBuilder2Impl::PuntCurrentRoot(
00442     CPKIFBasicPathState2* basicState, 
00444     IPKIFTrustAnchorList& oldRoots)
00445 {
00446     //copy the current roots into the oldRoots outbound parameter
00447     copy(basicState->m_rootList.begin(), basicState->m_rootList.end(), back_inserter(oldRoots));
00448 
00449     //attempts to build to the current root have proven fruitless - empty the root list
00450     basicState->m_rootList.clear();
00451 
00452     //clean up the state
00453     basicState->ClearState();
00454 }
00455 
00456 //----------------------------------------------------------------------------------------------------
00457 //  RemoveLoopMakers (called from PuntTopRow, GrowTable and BuildOrGrowTable)
00458 //      This function builds a partial path by taking the front node from each row
00459 //      and removes certs from the certList parameter object that would create a loop
00460 //      with any of those certs.  Comparison uses same DN/same public key logic.
00461 //----------------------------------------------------------------------------------------------------
00472 void CPKIFPathBuilder2Impl::RemoveLoopMakers(
00474     CPKIFCertificateNodeList& certList, 
00476     CPKIFBasicPathState2* basicState, 
00478     CPKIFCertificateNodeListWithSourceInfoPtr& currPos, 
00480     bool growingRow)
00481 {
00482     //if the table is empty then there are no "loop makers" - return immediately
00483     if(basicState->m_table.empty())
00484         return;
00485 
00486     //otherwise - iterate over the table and build a partial path taking the frontmost
00487     //node from each row in the table (It'd be a good idea to maintain a running partial
00488     //path so we can avoid repeated calls to setup and tear down the partial path list)
00489     CPKIFCertificateNodeList builtPath;
00490     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos = basicState->m_table.rbegin();
00491     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
00492     if(growingRow && pos != end)
00493         ++pos;//don't remove items that conflict with the current node closest to root
00494 
00495     CPKIFCertificatePtr currPosCert = currPos->front()->GetCert();
00496     while(pos != end && !(*pos)->empty() && !(*(*pos)->front()->GetCert() == *currPosCert))
00497     {
00498         ++pos;
00499     }
00500 
00501     //if(pos != end)
00502     //  ++pos;
00503 
00504     for(; pos != end; ++pos)
00505     {
00506         if(!(*pos)->empty())
00507             builtPath.push_back((*pos)->front());
00508     }
00509 
00510 #ifdef _DEBUG
00511     size_t size = certList.size();
00512 #endif
00513 
00514     //prepare a NodeInNodeList predicate object with the partial path that was just built
00515     NodeInNodeList n;
00516     n.SetNodeList(&builtPath);
00517 
00518     //invoke the remove_if alg using the NodeInNodeList object (i.e. iterate over
00519     //certList and move all entries that are present in the builtPath to the end 
00520     //of the list so they can be removed by the call to erase).
00521     CPKIFCertificateNodeList::iterator newEnd = remove_if(certList.begin(), certList.end(), n);
00522     certList.erase(newEnd, certList.end());
00523 
00524 #ifdef _DEBUG
00525     size = certList.size();
00526 #endif
00527 
00528     //next remove any duplicates from the current list
00529     //for(CPKIFCertificateNodeList::size_type ii = 0; ii < certList.size(); ++ii)
00530     //{
00531     //  for(CPKIFCertificateNodeList::size_type jj = ii+1; jj < certList.size(); ++jj)
00532     //  {
00533     //      if(*certList[ii] == *certList[jj])
00534     //      {
00535     //          certList.erase(certList.begin() + jj);
00536     //          jj = ii+1;
00537     //      }
00538     //  }
00539     //}
00540 }
00541 
00542 //----------------------------------------------------------------------------------------------------
00543 //  PuntTopRow
00544 //----------------------------------------------------------------------------------------------------
00552 bool CPKIFPathBuilder2Impl::PuntTopRow(
00554     CPKIFBasicPathState2* basicState,
00556     CPKIFNamePtr& prevName, 
00559     CPKIFCertificatePtr& curCert, 
00561     IPKIFCertRepository* iCert,
00563     IPKIFCertRepositoryUpdate* iCertUpdate, 
00565     IPKIFTrustCache* iTrust, 
00567     CPKIFPathSettingsPtr& settings)
00568 {
00569     //basicState holds the table of certs, prevName holds the name of the issuer we are giving up on
00570     //and curCert will be set to the curCert used for building upon exiting this function.
00571     //thus basicState - in/out; prevName - in; curCert - out
00572 
00573     //set curCert to NULL - we'll set it to an actual cert below if possible
00574     CPKIFCertificatePtr nullCert;
00575     curCert = nullCert; 
00576 
00577     //the top of the table is the end of the vector - iterate in reverse
00578     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos = basicState->m_table.rbegin();
00579     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
00580     do
00581     {
00582         //this loop should never punt the last row in the table
00583         for(; pos != end && (pos+1) != end; ++pos)
00584         {
00585             //before punting this row - see if it can be grown using remote sources
00586             if(LOCAL == (*pos)->m_maxSource && !(*pos)->empty() && (pos + 1) != end)
00587             {
00588                 LOG_STRING_INFO("Failed to find necessary certificates using LOCAL sources.  Checking REMOTE sources.", m_parent->thisComponent, 0, this);
00589                 if(GrowRow(*pos, iCert, iCertUpdate, basicState, curCert, iTrust, settings, *(pos + 1)))
00590                     break;
00591             }
00592 
00593             //get the name of the subject at the front of the current row
00594             CPKIFNamePtr tmpName = (*pos)->front()->GetCert()->Subject();
00595 
00596 #ifdef _DEBUG
00597             const char* curCertIssuerString = prevName->ToString();
00598             const char* curCertSubjectString = tmpName->ToString();
00599             size_t size = (*pos)->size();
00600 #endif
00601 
00602             //remove all certs in the current row that were issued by prevName
00603             RemoveAllIssuedBy(*pos, prevName);
00604 
00605 #ifdef _DEBUG
00606             size = (*pos)->size();
00607 #endif
00608 
00609             //update the previous name to the name of the front cert of the current row
00610             //it will be used to thin the next row if this row went empty on the above
00611             //remove call
00612             prevName = tmpName;
00613 
00614             //if the current row is not empty after the above remove call then there's still hope
00615             if(!(*pos)->empty())
00616                 break;
00617         }
00618 
00619         //if pos != end then set the curCert to the front cert on the pos row (this will cause loop termination
00620         if(pos != end && (pos+1) != end)
00621             curCert = (*pos)->front()->GetCert(); 
00622         else
00623             break;//if pos == end break out by force
00624     }while(curCert == (CPKIFCertificate*)NULL);
00625 
00626     //look at each row in the table and delete those that are empty
00627     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::iterator newEnd = remove_if(basicState->m_table.begin(), basicState->m_table.end(), IsEmpty);
00628     basicState->m_table.erase(newEnd, basicState->m_table.end());
00629 
00630 //#ifdef _DEBUG_PATH
00631     //cout << endl << "Dumping table from PuntTopRow" << endl;
00632     //DumpTable(basicState->m_table, "PuntTopRow");
00633 //#endif
00634 
00635     //if we exited the above loop with curCert == NULL then building is done (and failed)
00636     if(curCert == (IPKIFNameAndKey*)NULL || basicState->m_table.size() == 0)
00637         return false;
00638     else 
00639     {
00640         basicState->m_bInitCompleteLocal = false; //this isn't true for roots after first root 
00641         return true;//otherwise - we can continue trying to build
00642     }
00643 }
00644 
00645 //----------------------------------------------------------------------------------------------------
00646 //  PuntFailure
00647 //----------------------------------------------------------------------------------------------------
00655 bool CPKIFPathBuilder2Impl::PuntFailure(
00657     CPKIFBasicPathState2* basicState, 
00659     CPKIFCertificateNodeEntryPtr& ppPos)
00660 {
00661     //This function will remove the node in ppPos from the table of nodes from which we build paths.
00662     //If removal of the node causes the list to become empty then the row and all rows from it to the root are removed
00663     CPKIFNamePtr nodeName = ppPos->GetCert()->Subject();
00664     CPKIFNamePtr nextNodeName;
00665     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos = basicState->m_table.rbegin();
00666     vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
00667     for(; pos != end; ++pos)
00668     {
00669         CPKIFNamePtr tmpName = (*pos)->front()->GetCert()->Subject();
00670 
00671 #ifdef _DEBUG
00672         const char* curNodeString = nodeName->ToString();
00673         const char* curCertSubjectString = tmpName->ToString();
00674 #endif
00675 
00676         if(*tmpName == *nodeName)
00677         {
00678             size_t size = (*pos)->size();
00679             GottaMatch<CPKIFCertificateNodeEntryPtr > gm;
00680             gm.SetRHS(ppPos);
00681             //changed iterator declaration 11/23/2004
00682             CPKIFCertificateNodeListWithSourceInfo::iterator newEnd = remove_if((*pos)->begin(), (*pos)->end(), gm);
00683             (*pos)->erase(newEnd, (*pos)->end());
00684 
00685             size = (*pos)->size();
00686             if(0 == size)
00687             {
00688                 //we've emptied a row in our table so we should remove the top
00689                 basicState->m_rootList.clear();
00690 
00691                 //remove the cert in the previous row that caused the violater to be retrieved
00692                 int indexer = 0;
00693                 
00694                 do
00695                 {
00696                     ++indexer;
00697 
00698                     //if the next row is the end then break
00699                     if((pos+indexer) == end)
00700                         break;
00701 
00702                     //get the name of the front cert in the next row
00703                     nextNodeName = (*(pos+indexer))->front()->GetCert()->Subject();
00704 
00705                     //this may cause the last row in the table to be removed.  this is OK since it means the target was the cause of the failure.
00706                     //otherwise remove all nodes in the next row issued by nodeName 
00707                     RemoveAllIssuedBy(*(pos+indexer), nodeName);
00708 
00709                     //set up nodeName for next iteration
00710                     nodeName = nextNodeName;
00711                 }while(0 == (*(pos+indexer))->size()); //keep going until end of table as long as rows continue to be made empty
00712 
00713                 vector<CPKIFCertificateNodeListWithSourceInfoPtr>::iterator newEnd = find_if(basicState->m_table.begin(), basicState->m_table.end(), IsEmpty);
00714                 basicState->m_table.erase(newEnd, basicState->m_table.end());
00715             }
00716             break;
00717         }
00718     }
00719 
00720     if(0 == basicState->m_table.size())
00721         return false;
00722     else 
00723     {
00724         return true;
00725     }
00726 }
00727 
00728 //----------------------------------------------------------------------------------------------------
00729 //  SearchForFailure
00730 //----------------------------------------------------------------------------------------------------
00738 void CPKIFPathBuilder2Impl::SearchForFailure(
00740     CPKIFBasicPathState2* basicState, 
00742     CPKIFCertificateNodeList& prevPath,
00743     CPKIFPathSettingsPtr& settings)
00744 {
00745     CPKIFGeneralSubtreeListPtr perm, excl;
00746     settings->GetInitialPermSubtrees(perm);
00747     settings->GetInitialExclSubtrees(excl);
00748     bool permHasBeenSet = false;
00749     if(perm)
00750         permHasBeenSet = true;
00751 
00752     CPKIFCertificateNodeList::iterator ppPos;   
00753     CPKIFCertificateNodeList::iterator ppEnd = prevPath.end();
00754     bool removeTheOffendingCert = false;
00755     for(ppPos = prevPath.begin(); ppPos != ppEnd; ++ppPos)
00756     {
00757         CPKIFCertStatusPtr status = (*ppPos)->GetStatus();
00758 
00759         if(status)
00760         {
00761             //these are events that allow us to remove a cert from further consideration
00762             //with the current set of certs above it
00763             if(PATH_NAME_CONSTRAINTS_VIOLATION == status->GetDiagnosticCode())
00764             {
00765                 CPKIFCertificatePtr cert = (*ppPos)->GetCert();
00766                 if(!CheckNameConstraints(cert, perm, excl, permHasBeenSet))
00767                     removeTheOffendingCert = true;
00768                 break;
00769             }
00770             else if(REVOKED == status->GetRevocationStatus())
00771             {
00772                 removeTheOffendingCert = true;
00773                 break;
00774             }
00775             else if(ppPos == ppEnd -1 && 
00776                 (PATH_VALIDITY_PERIOD_VIOLATION_NOT_YET_VALID == status->GetDiagnosticCode()
00777                 || PATH_VALIDITY_PERIOD_VIOLATION_EXPIRED == status->GetDiagnosticCode()))
00778             {
00779                 removeTheOffendingCert = true;
00780                 break;
00781             }
00782         }
00783     }
00784 
00785     if(ppPos != ppEnd)
00786     {
00787         if(removeTheOffendingCert)
00788         {
00789             //remove the cert that caused the failure
00790             PuntFailure(basicState, *ppPos);
00791         }
00792         else
00793             (*ppPos)->SetIgnore();
00794     }
00795 }
00796 
00797 //----------------------------------------------------------------------------------------------------
00798 //  BuildOrGrowTable
00799 //----------------------------------------------------------------------------------------------------
00812 bool CPKIFPathBuilder2Impl::BuildOrGrowTable(
00814     CPKIFBasicPathState2* basicState, 
00816     CPKIFPathSettingsPtr& settings, 
00818     CPKIFCertificatePtr& curCert,
00820     CPKIFCertificateNodeList& prevPath)
00821 {
00822     //----------------------------------------------------------------------------------------------------
00823     //  COLLECT INTERFACES
00824     //----------------------------------------------------------------------------------------------------
00825     //query for the various interfaces we will need:
00826     //  need: IPKIFCertRepository, IPKIFTrustCache
00827     //  use (if present): IPKIFCertRepositoryUpdate, IPKIFCRLRepository
00828     //  future:   ICACPathCache
00829     IPKIFCertRepository* iCert = m_parent->GetMediatorFromParent<IPKIFCertRepository>();
00830     IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
00831     if(NULL == iCert || NULL == iTrust)
00832         throw CPKIFPathException(m_parent->thisComponent, COMMON_MEDIATOR_MISSING, "IPKIFCertRepository and/or IPKIFTrustCache are not available.");
00833 
00834     //the cert update interface can be absent (if it's present we'll use it)
00835     IPKIFCertRepositoryUpdate* iCertUpdate = m_parent->GetMediatorFromParent<IPKIFCertRepositoryUpdate>();
00836 
00837     //likewise for the CRL interface
00838     IPKIFCRLRepository* iCRL = m_parent->GetMediatorFromParent<IPKIFCRLRepository>();
00839 
00840     //this interface doesn't exist - but we'll query for it anyway to recall the days when it's existance was anticipated (or not)
00841     //ICACPathCache* iPath = GetMediatorFromParent<ICACPathCache>();
00842 
00843     bool skipRootCheck = false; //this flag is used to indicate that we just punted a root and should try alternatives from top row of table
00844     //eliminate template and always use the default scoring class
00845     CPKIFDefaultScoring s;
00846     //Scoring s;    //create an object of the type defined by the template parameter
00847 
00848     IPKIFTrustAnchorList oldRoots;
00849 
00850     //see if the root list is empty - if not try to grow the table or get rid of the root (and any other garbage)
00851     if(!basicState->m_rootList.empty())
00852     {
00853         //try to add to the table using additional sources
00854         if(GrowTable(basicState, iCert, iCertUpdate, iTrust, settings))
00855             return true;
00856 
00857         //if we failed to add any new entries then punt the current root
00858         PuntCurrentRoot(basicState, oldRoots);
00859         skipRootCheck = true; //there may be alternatives to using top row to trust root connection
00860 
00861         //the top of the table is the end of the vector.  take the front cert from the top row
00862         //by taking the front cert from the last entry in the vector
00863         if(!basicState->m_table.empty() && !basicState->m_table.back()->empty())
00864             curCert = basicState->m_table.back()->front()->GetCert();
00865         else
00866         {
00867             return false;//we're done
00868         }
00869     }
00870     else if(curCert == (CPKIFCertificate*)NULL)
00871     {
00872         return false;
00873     }
00874 
00875     //we're rootless - create a new empty root list to realize that fact
00876     IPKIFTrustAnchorList trustRootList;
00877     CPKIFNamePtr curCertIssuer, curCertSubject;
00878     
00879     //when we find a path we'll set this guy to true - for now (s)he's false (pause to ponder the gender of variables)
00880     bool foundPath = false;
00881 
00882     PKIInfoSource oldSource = basicState->m_maxSource;
00883 
00884     size_t tableSize = 0;
00885     do
00886     {
00887         
00888         tableSize = basicState->m_table.size(); //harvest table size for use by scoring function
00889         curCertIssuer = curCert->GetIssuerName();       //save the issuer of the current cert
00890 
00891 #ifdef _DEBUG
00892         curCertSubject = curCert->GetSubjectName(); 
00893         const char* curCertIssuerString = curCertIssuer->ToString();
00894         const char* curCertSubjectString = curCertSubject->ToString();
00895 #endif
00896 
00897         //only look for trust roots when we didn't just punt the root row (otherwise we'll sit and spin)
00898         if(!skipRootCheck && iTrust->GetTrustRoots(curCertIssuer, trustRootList))
00899         {
00900             KeyIDCompare keyIDComp;
00901             keyIDComp.SetCurrent(curCert);  
00902             sort(trustRootList.begin(), trustRootList.end(), keyIDComp);
00903 
00904             //we've found a trust root so we can return a path
00905             basicState->SetTrustRoot(trustRootList);
00906 
00907             foundPath = true;
00908             break;
00909         }
00910         else
00911         {
00912             skipRootCheck = false;  //reset so we'll look for roots next pass
00913 
00914             CPKIFCertificateNodeList certList;
00915             //CPKIFCertificateList certList;
00916 
00917             //the cur cert is not issued by a trust root (more or less) - look for certs elsewhere
00918             //iCert->GetCertificates(curCertIssuer, certList, basicState->m_maxSource);
00919             iCert->GetCertificates(curCert, certList, basicState->m_maxSource);
00920             size_t certListSize = certList.size();
00921             do
00922             {
00923                 if((0 == certListSize || LOCAL < basicState->m_maxSource) && NULL != basicState->m_reserved /*&& LOCAL == basicState->m_maxSource*/)
00924                 {
00925                     LOG_STRING_INFO("Failed to find necessary certificates using LOCAL sources.  Checking REMOTE sources.", m_parent->thisComponent, 0, this);
00926 
00927                     //moved down here from above so it is only invoked when REMOTE sources are considered
00928                     //GetCertsFromIssuerAltName(*curCert, certList, REMOTE); //added 04/17/2003 CRW
00929 
00930                     //if local failed to produce results - try remote
00931                     //iCert->GetCertificates(curCertIssuer, certList, REMOTE);
00932                     iCert->GetCertificates(curCert, certList, REMOTE);
00933                     certListSize = certList.size();
00934                     //if(0 != certListSize)
00935                         basicState->m_maxSource = ALL;//only bump this if we found some certs (if we didn't we may still be able to build through the cache)
00936                 }
00937 
00938                 if(0 != certListSize)
00939                 {
00940                     //remove any certs that would create a loop with certs already in the path
00941                     RemoveLoopMakers(certList, basicState, *basicState->m_table.rbegin());
00942 
00943                     //added 12/4
00944                     IPKIFTrustAnchorList::iterator orPos;
00945                     IPKIFTrustAnchorList::iterator orEnd = oldRoots.end();
00946                     for(orPos = oldRoots.begin(); orPos != orEnd; ++orPos)
00947                     {
00948                         //if we just punted a specific root - don't use it again
00949                         //not accounting for non-cert TAs in this case
00950                         CPKIFCertificatePtr taCert = (*orPos)->GetCertificate();
00951                         if(taCert)
00952                         {
00953                             CPKIFCertificateNodeEntryPtr newNode(new CPKIFCertificateNodeEntry);
00954                             newNode->SetCert(taCert);
00955 
00956                             GottaMatch<CPKIFCertificateNodeEntryPtr> orGM;
00957                             orGM.SetRHS(newNode);
00958 
00959                             CPKIFCertificateNodeList::iterator newEnd = remove_if(certList.begin(), certList.end(), orGM);
00960                             certList.erase(newEnd, certList.end());
00961                         }
00962                     }
00963 
00964                     certListSize = certList.size();
00965                 }
00966             }
00967             while(0 == certListSize && LOCAL == basicState->m_maxSource && NULL != basicState->m_reserved);//added do/while 7/24/2004
00968 
00969             if(0 == certListSize)
00970             {
00971                 //if we found no certs (or all of the found certs created loops) then punt the top row
00972                 PuntTopRow(basicState, curCertIssuer, curCert, iCert, iCertUpdate, iTrust, settings);
00973                 //Added to fix a problem when building in a bridge environment using only local store Armen 7/20/06
00974                 if(basicState->m_maxSource == REMOTE)
00975                     basicState->m_maxSource = ALL;
00976             }
00977             else
00978             {
00979                 //code in this block is very similar to code in GrowRow - if modify here investigate there
00980 
00981                 //first convert the list of certs to a list of certnodes (i.e.
00982                 //wrap the certs in a container that has information to guide
00983                 //building and validation given the current settings)
00984                 CPKIFCertificateNodeListWithSourceInfoPtr tmpNodeList(new CPKIFCertificateNodeListWithSourceInfo);
00985                 tmpNodeList->m_maxSource = basicState->m_maxSource;
00986                 CPKIFCertificateNodeList::iterator pos;
00987                 CPKIFCertificateNodeList::iterator end = certList.end();
00988                 for(pos = certList.begin(); pos != end; ++pos)
00989                 {
00990                     //make sure we ignore certs for other folks that may have been in the directory
00991                     if(*curCertIssuer == *(*pos)->GetCert()->Subject())
00992                     {
00993                         GottaMatch<CPKIFCertificateNodeEntryPtr> gm;
00994                         gm.SetRHS(*pos);
00995                         if(tmpNodeList->end() == find_if(tmpNodeList->begin(), tmpNodeList->end(), gm))
00996                         {
00997                             //if we found certs - add them to the cache
00998                             if(iCertUpdate && LOCAL != (*pos)->GetSource())
00999                             {
01000                                 try
01001                                 {
01002                                     iCertUpdate->AddCertificate(CA, *pos);
01003                                 }
01004                                 catch(CPKIFException& )
01005                                 {
01006                                     //delete e;//don't fail because we have no in-memory cache or whatever
01007                                 }
01008                             }
01009 
01010                             tmpNodeList->push_back(*pos);
01011                         }
01012                     }
01013                 }
01014 
01015                 //sort the certs in the node and set curCert to the best
01016                 //reviewed 4/24 - the path depth is governed by an integer value so size_t should never exceed that value (or even come close)
01017                 
01018                 int size = 0;
01019                 try 
01020                 {
01021                     size = numeric_cast<int>(basicState->m_table.size());
01022                 }
01023                 catch(bad_numeric_cast &) 
01024                 {
01025                     throw CPKIFException(TOOLKIT_PATH, COMMON_INVALID_INPUT, "Table size is an impossibly long number.");
01026                 }
01027                 s.ScoreAndSortNodes(tmpNodeList, curCert, settings, iTrust, size - 1, iCert);//-1 to not count target cert
01028 
01029                 //added table size check (Armen) 7/20/2004
01030                 size_t stDepth = settings->GetDepth();
01031                 if(0 != tmpNodeList->size() && tableSize < stDepth)
01032                 {
01033                     basicState->m_table.push_back(tmpNodeList);
01034                     curCert = tmpNodeList->front()->GetCert(); 
01035                 }
01036                 else
01037                 {
01038                     PuntTopRow(basicState, curCertIssuer, curCert, iCert, iCertUpdate, iTrust, settings);
01039                     //Added to fix a problem when building in a bridge environment using only local store Armen 7/20/06
01040                     if(basicState->m_maxSource == REMOTE)
01041                         basicState->m_maxSource = ALL;
01042                 }
01043             }
01044 
01045             if(curCert == (CPKIFCertificate*)NULL)
01046                 break;
01047         }
01048     }while(1);
01049 
01050     if(curCert == (CPKIFCertificate*)NULL)
01051         return false;
01052     else
01053     {
01054         if(oldSource != basicState->m_maxSource)
01055         {
01056             //if we changed from LOCAL to REMOTE in the above loop make sure all rows are
01057             //using the same max source so we can easily screen for previously returned paths
01058             //following a table expansion
01059             GrowTable(basicState, iCert, iCertUpdate, iTrust, settings);
01060         }
01061         if(0 == basicState->m_nGrowCount && LOCAL == basicState->m_maxSource)
01062             basicState->m_bInitCompleteLocal = true;
01063 
01064         ++basicState->m_nGrowCount;
01065 
01066         vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos;
01067         vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
01068         CPKIFNamePtr issuerName = basicState->m_rootList.front()->GetSubjectName();
01069         for(pos = basicState->m_table.rbegin(); pos != end; ++pos)
01070         {
01071             IgnoreNotIssuedBy(*pos, issuerName);
01072             issuerName = (*pos)->front()->GetCert()->Subject();
01073         }
01074 
01075         return true;
01076     }
01077 }
01078 
01079 //----------------------------------------------------------------------------------------------------
01080 //  CheckAlternatives
01081 //----------------------------------------------------------------------------------------------------
01093 bool CPKIFPathBuilder2Impl::CheckAlternatives(
01095     CPKIFCertificatePath& path,
01097     CPKIFBasicPathState2* basicState)
01098 {
01099     //if the table is incomplete (i.e. there is no root) return false
01100     //check for empty table added to account for cases where target was popped by PuntFailure
01101     if(basicState->m_rootList.empty() || 0 == basicState->m_table.size())
01102         return false;
01103     CPKIFBuilderStatisticsPtr bs;
01104     path.GetBuilderStats(bs);
01105 
01106     do
01107     {
01108         if(basicState->m_curRoot == NULL)
01109         {
01110             //we haven't been here before
01111             basicState->m_curRoot = &basicState->m_rootList.front();
01112         }
01113         else
01114         {
01115             //if we didn't move the ignore pointer on the root row
01116             vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator tablePos;
01117             vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator tableEnd = basicState->m_table.rend();
01118             for(tablePos = basicState->m_table.rbegin(); tablePos != tableEnd; ++tablePos)
01119             {
01120                 if(!SetNextToIgnore(*tablePos))
01121                 {
01122                     //if we do not need to advance the row then break out of this loop
01123                     break;
01124                 }
01125                 else
01126                 {
01127                     //if we do need to advance the row the clear all ignored flags in the current row
01128                     ClearAllIgnore(*tablePos);
01129                 }
01130             }
01131             if(tablePos == tableEnd)
01132             {
01133                 bool liveMore = false;
01134 
01135                 //advance the ignored pointer in the trust root list (if there's more than one root)
01136                 if(basicState->m_rootList.size() > 1)
01137                 {
01138                     bool setNext = false;
01139                     IPKIFTrustAnchorList::iterator rootPos;
01140                     IPKIFTrustAnchorList::iterator rootEnd = basicState->m_rootList.end();
01141                     for(rootPos = basicState->m_rootList.begin(); rootPos != rootEnd; ++rootPos)
01142                     {
01143                         if(setNext)
01144                         {
01145                             basicState->m_curRoot = &(*rootPos);
01146                             liveMore = true;
01147                             break;
01148                         }
01149                         else
01150                         {
01151                             if(basicState->m_curRoot == &(*rootPos))
01152                                 setNext = true;
01153                         }
01154                     }
01155                 }
01156                 
01157                 if(!liveMore)
01158                     return false;//no more alternatives in this table - return false
01159             }
01160         }
01161 
01162 //#ifdef _DEBUG_PATH
01163         //DumpTable(basicState->m_table, "CheckAlternatives");
01164 //#endif
01165         //this code iterates over the table and populates builtPath with the first non-ignored
01166         //node that isn't already in the path (same DN/same public key) that was issued by the previous
01167         //node in the list.
01168         CPKIFCertificateNodeList builtPath;
01169         vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator pos;
01170         vector<CPKIFCertificateNodeListWithSourceInfoPtr>::reverse_iterator end = basicState->m_table.rend();
01171         CPKIFCertificateNodeEntryPtr curEntry;
01172         bool hasCycle = false;
01173         PKIInfoSource pathMaxSource = LOCAL;
01174         CPKIFNamePtr issuerName = (*basicState->m_curRoot)->GetSubjectName();
01175 
01176         IPKIFNameAndKey* lastCert = dynamic_cast<IPKIFNameAndKey*>(&(*(*basicState->m_curRoot)));
01177         IPKIFNameAndKey* taCert = lastCert;
01178 
01179         CPKIFPathSettingsPtr settings; 
01180         path.GetPathSettings(settings);
01181 
01182         for(pos = basicState->m_table.rbegin(); pos != end; ++pos)
01183         { 
01184             curEntry = GetFirstNonIgnoredNodeNotAlreadyInPathIssuedBy(*pos, builtPath,lastCert,settings);
01185             if(curEntry != (CPKIFCertificateNodeEntry*)NULL     //check for NULL
01186                 && !curEntry->GetCert()->SameDNSameKey(*taCert))    //make sure TA DN and key are not repeated
01187             {
01188                 builtPath.push_back(curEntry);
01189 
01190                 lastCert = NULL;
01191                 lastCert = dynamic_cast<IPKIFNameAndKey*>(&(*curEntry->GetCert()));
01192                 //issuerName = lastCert->Subject();
01193                 if(pathMaxSource < curEntry->GetSource())
01194                     pathMaxSource = curEntry->GetSource();
01195             }
01196             else
01197             {
01198                 if(curEntry)
01199                     curEntry->SetIgnore();
01200 
01201                 hasCycle = true; //this path has a cycle - try another
01202                 break;
01203             }
01204         }
01205 
01206         //move this from here to below the two continue statements to correct counts reported by builder stats
01207 //      ++bs->m_nTotalPathsDiscovered;
01208 
01209 #ifdef _DEBUG_PATH_DUMP
01210         {
01211             if(!g_pathLogFile.is_open())
01212             {
01213                 g_pathLogFile.open("_DEBUG_PATH_DUMP_PathLog.txt", ios::out);
01214             }
01215             CPKIFCertificatePath dbgpath;
01216             dbgpath.SetPath(builtPath);
01217             CPKIFPathLogger pl;
01218             pl.LogPath(dbgpath, "_DEBUG_PATH_DUMP", &g_pathLogFile);
01219             if(hasCycle)
01220                 g_pathLogFile << "HasCycle = true" << endl;
01221             else
01222                 g_pathLogFile << "HasCycle = false" << endl;
01223         }
01224 #endif
01225 
01226         //if the effort to build through current table state produced a cycle 
01227         //give another pass through the do...while by moving the ignored pointer
01228         if(hasCycle)
01229             continue;
01230 
01231         //if we were able to initially complete the table locally and the table has grown
01232         //we can disregard paths built totally from the local source because they've already been tried
01233         if(/*basicState->m_bInitCompleteLocal && */pathMaxSource == LOCAL && NULL != basicState->m_reserved)//pathMaxSource < basicState->m_maxSource)
01234             continue;
01235 
01236         ++bs->m_nTotalPathsDiscovered;
01237 
01238         //perform basic validation checks
01239         CPKIFPathValidationResults tmpResults;
01240         if(settings->GetUseValidatorFilterWhenBuilding() && !PathOK(builtPath, *basicState->m_curRoot, settings, tmpResults))
01241         {
01242             ++bs->m_nPathsRejectedDueToValidationErrors;
01243             bs->m_vFailureCodes.push_back(tmpResults.DiagnosticCode());
01244             SearchForFailure(basicState, builtPath, settings);
01245 
01246             CPKIFCertificatePath tmpPath;
01247             CPKIFCertificatePtr tmpTarget;
01248             path.GetTarget(tmpTarget);
01249             tmpPath.SetTrustRoot(*basicState->m_curRoot);
01250             tmpPath.SetPath(builtPath);
01251             tmpPath.SetTarget(tmpTarget);
01252 
01253             CPKIFPathLogger::LogValidationResults(tmpResults, tmpPath, "Logging builder-rejected path"); //added 04/18/2003 CRW
01254             continue;
01255         }
01256 
01257         path.SetTrustRoot(*basicState->m_curRoot);
01258         path.SetPath(builtPath);
01259 
01260         /*
01261         CPKIFCertificateNodeList::iterator dbgpos;
01262         CPKIFCertificateNodeList::iterator dbgend = builtPath.end();
01263     #ifdef _DEBUG_PATH
01264         cout << endl << "Returning path from CheckAlternatives..." << endl;
01265         cout << "Root: " << (*(basicState->m_curRoot))->GetSubjectName()->ToString() << endl;
01266     #endif
01267         if(LOCAL == pathMaxSource)
01268         {
01269             LOG_STRING_DEBUG("Printing path returned from BuildPath (LOCAL-certs only)...", m_parent->thisComponent, 0, NULL);
01270         }
01271         else
01272         {
01273             LOG_STRING_DEBUG("Printing path returned from BuildPath (LOCAL and REMOTE certs)...", m_parent->thisComponent, 0, NULL);
01274         }
01275         std::string logStr = "Root: ";
01276         logStr.append((*(basicState->m_curRoot))->GetSubjectName()->ToString());
01277         LOG_STRING_DEBUG(logStr.c_str(), m_parent->thisComponent, 0, NULL);
01278 
01279         for(dbgpos = builtPath.begin(); dbgpos != dbgend; ++dbgpos)
01280         {
01281             const char* curCertString = (*dbgpos)->GetCert()->Subject()->ToString();
01282     #ifdef _DEBUG_PATH
01283             cout << curCertString << " " << (*dbgpos)->GetCert()->SerialNumber() << endl;
01284     #endif
01285             logStr = curCertString;
01286             logStr.append(" ");
01287             logStr.append((*dbgpos)->GetCert()->SerialNumber());
01288             LOG_STRING_DEBUG(logStr.c_str(), m_parent->thisComponent, 0, NULL);
01289         }
01290         */
01291         ++bs->m_nReturnedPaths;
01292         return true;
01293     }while(1);
01294 }
01295 
01296 //----------------------------------------------------------------------------------------------------
01297 //
01298 //  Public interface functions
01299 //
01300 //----------------------------------------------------------------------------------------------------
01301 //This function will build a path to the target specified by the path parameter, using the settings
01302 //specified by the path parameter, using the state specified by the path parameter (as set by previous calls
01303 //to this function).
01322 bool CPKIFPathBuilder2::BuildPath(
01326                           CPKIFCertificatePath& path)
01327 { 
01328     LOG_STRING_DEBUG("CPKIFPathBuilder2::BuildPath(CPKIFCertificatePath& path)", thisComponent, 0, this);
01329 
01330     //----------------------------------------------------------------------------------------------------
01331     //  STATE SETUP
01332     //----------------------------------------------------------------------------------------------------
01333     //require that settings be non-NULL
01334     CPKIFPathSettingsPtr settings;
01335     path.GetPathSettings(settings);
01336     if(settings == (CPKIFPathSettings*)NULL)
01337         RAISE_PATH_EXCEPTION("Path parameter contained NULL path settings.", thisComponent, COMMON_INVALID_INPUT, this)
01338 
01339     //prepare state - first check to see if state was passed in and if it belongs to us
01340     CPKIFCertificatePathStatePtr state;
01341     CPKIFBasicPathState2* basicState = NULL;
01342     path.GetState(state);
01343 
01344     //if there was state - see if we can cast it to a type that this builder uses
01345     if(state != (CPKIFCertificatePathState*)NULL)
01346         basicState = dynamic_cast<CPKIFBasicPathState2* >(&(*state));
01347 
01348     //if there was no state or the cast failed create a new state and put it in the path
01349     if(NULL == basicState)
01350     {
01351         //allocate the new state... (throw bad_alloc)
01352         basicState = new CPKIFBasicPathState2;      
01353 
01354         //and builder statistics (throw bad_alloc)
01355         CPKIFBuilderStatisticsPtr bs(new CPKIFBuilderStatistics);
01356 
01357         path.SetBuilderStats(bs);
01358 
01359         //store it in the path
01360         CPKIFCertificatePathStatePtr tmpState(basicState);
01361         path.SetState(tmpState);
01362     }
01363 
01364     //----------------------------------------------------------------------------------------------------
01365     //  PREPARATORY STEPS
01366     //----------------------------------------------------------------------------------------------------
01367     //get the target cert as cur cert if path is empty
01368     CPKIFCertificatePtr curCert;
01369     CPKIFCertificateNodeList prevPath; 
01370     path.GetPath(prevPath);
01371 
01372     //see if the previous path is non-empty (i.e. we've been here before)
01373     if(prevPath.empty())
01374     {
01375         //if prevPath is empty, get things ready for the table builder function
01376         path.GetTarget(curCert);
01377         if(curCert == (CPKIFCertificate*)NULL)
01378             RAISE_PATH_EXCEPTION("The path parameter did not specify a target certificate.", thisComponent, COMMON_INVALID_INPUT, this)
01379 
01380         //prepare the list of lists with an entry for the target
01381         CPKIFCertificateNodeListWithSourceInfoPtr targetList(new CPKIFCertificateNodeListWithSourceInfo);
01382         CPKIFCertificateNodeEntryPtr tmpNode(new CPKIFCertificateNodeEntry);
01383         tmpNode->SetCert(curCert);
01384         targetList->push_back(tmpNode);
01385 
01386         //first entry in the table is always a one node list with the target
01387         basicState->m_table.clear();
01388         basicState->m_table.push_back(targetList);
01389 
01390         //check to see if the target is a trust root (if so we can stop building now)
01391         IPKIFTrustCache* iTrust = GetMediatorFromParent<IPKIFTrustCache>();
01392         if(NULL == iTrust)
01393             RAISE_PATH_EXCEPTION("IPKIFTrustCache interface not available.", thisComponent, COMMON_MEDIATOR_MISSING, this)
01394 
01395         IPKIFTrustAnchorList tmpRootList;
01396         iTrust->GetTrustRoots(curCert->GetSubjectName(), tmpRootList);
01397         if(!tmpRootList.empty())
01398         {
01399             //iterate over the roots and see if any match the target
01400             IPKIFTrustAnchorList::iterator rootPos;
01401             IPKIFTrustAnchorList::iterator rootEnd = tmpRootList.end();
01402             for(rootPos = tmpRootList.begin(); rootPos != rootEnd; ++rootPos)
01403             {
01404                 IPKIFNameAndKey* taNameAndKey = dynamic_cast<IPKIFNameAndKey*>(&(*(*rootPos)));
01405                 IPKIFNameAndKey* certNameAndKey = dynamic_cast<IPKIFNameAndKey*>(&(*curCert));
01406                 if(*certNameAndKey == *taNameAndKey)
01407                 {
01408                     //if we find a trust root that matches the target then we're done
01409                     //set the trust root on the path
01410                     path.SetTrustRoot(*rootPos);
01411 
01412                     //then set the path to a list containing only the target
01413                     CPKIFCertificateNodeList builtPath;
01414                     CPKIFCertificateNodeEntryPtr curEntry(new CPKIFCertificateNodeEntry);
01415                     curEntry->SetCert(curCert);
01416 
01417                     CPKIFCertStatusPtr newStatus(new CPKIFCertStatus);
01418                     newStatus->SetIsTrustAnchor(true);
01419                     curEntry->SetStatus(newStatus);
01420 
01421                     builtPath.push_back(curEntry);
01422                     path.SetPath(builtPath);
01423                     basicState->SetTrustRoot(tmpRootList);
01424 
01425                     std::ostringstream os;
01426                     os << "Path building is not required.  The target certificate is a trust root - subject DN = " << curCert->GetSubjectName()->ToString();
01427                     LOG_STRING_INFO(os.str().c_str(), thisComponent, 0, this);
01428 
01429                     return true;
01430                 }
01431             }
01432         }
01433     }
01434     else
01435     {
01436         //look for any obvious failure causes
01437         m_impl->SearchForFailure(basicState, prevPath, settings);
01438     }
01439 
01440     //if the previous path was non-empty or if we set things up (and the target != a trust root)
01441     //then set the tableComplete bool to false (possibly not true but we'll check for alternatives
01442     //first) then begin building
01443     bool tableComplete = false; 
01444     do
01445     {
01446         //----------------------------------------------------------------------------------------------------
01447         //  INVESTIGATE ALTERNATIVES IN CURRENT TABLE
01448         //----------------------------------------------------------------------------------------------------
01449         //check to see if there are any more paths to try amongst any previously returned certs
01450         if(m_impl->CheckAlternatives(path, basicState))
01451             return true;
01452 
01453         //----------------------------------------------------------------------------------------------------
01454         //  BUILD A NEW TABLE OR TRY TO EXPAND IN CURRENT TABLE VIA ADDITIONAL LOCATIONS
01455         //----------------------------------------------------------------------------------------------------
01456         tableComplete = m_impl->BuildOrGrowTable(basicState, settings, curCert, prevPath);
01457         if(!tableComplete && NULL == basicState->m_reserved)
01458         {
01459             //if we get here and the table is empty, then the end entity cert was purged.  no need to carry on.
01460             if(basicState->m_table.empty())
01461                 return false;
01462 
01463             basicState->m_rootList.clear();
01464             basicState->m_bInitCompleteLocal = false;
01465             basicState->m_nGrowCount = 0;
01466 
01467             basicState->m_curRoot = NULL;
01468 
01469             basicState->m_maxSource = LOCAL;
01470             basicState->m_reserved = new char[1];
01471 
01472             CPKIFCertificateNodeListWithSourceInfoPtr targetList(new CPKIFCertificateNodeListWithSourceInfo);
01473             CPKIFCertificateNodeEntryPtr tmpNode(new CPKIFCertificateNodeEntry);
01474             path.GetTarget(curCert);
01475             tmpNode->SetCert(curCert);
01476             targetList->push_back(tmpNode);
01477 
01478             //first entry in the table is always a one node list with the target
01479             basicState->m_table.clear();
01480             basicState->m_table.push_back(targetList);
01481 
01482             tableComplete = m_impl->BuildOrGrowTable(basicState, settings, curCert, prevPath);
01483         }
01484     }while(tableComplete);
01485 
01486     //no more paths - we could no longer grow the table and the current alternatives have been exhausted
01487     return false;
01488 }

Generated on Mon Nov 15 11:15:55 2010 for PublicKeyInfrastructureFramework(PKIF) by  doxygen 1.5.6