PKIFReversiblePathBuilder.cpp

Go to the documentation of this file.
00001 
00010 #include "ASN1Helper.h"
00011 #include "BasicChecksUtils.h"
00012 #include "BasicConstraints.h"
00013 #include "BuilderStatistics.h"
00014 #include "BuilderUtils.h"
00015 #include "Certificate.h"
00016 #include "GottaMatch.h"
00017 #include "Name.h"
00018 #include "PathResults.h"
00019 #include "IPKIFCertRepository.h"
00020 #include "IPKIFCertRepositoryUpdate.h"
00021 #include "IPKIFTrustCache.h"
00022 #include "IPKIFCRLRepository.h"
00023 #include "IPKIFNameAndKey.h"
00024 #include "IPKIFSupportsSynonymousSources.h"
00025 #include "IssuedBy.h"
00026 #include "NodeInNodeList.h"
00027 #include "PKIFCertificateNodeEntry.h"
00028 #include "PKIFCertificatePath.h"
00029 #include "PKIFCertStatus.h"
00030 #include "PKIFErrors.h"
00031 #include "PKIFMediators.h"
00032 #include "PKIFNameAndKeyWithScore.h"
00033 #include "PKIFPathException.h"
00034 #include "PKIFPathLogger.h"
00035 #include "PKIFPathSettings.h"
00036 #include "PKIFReversiblePathBuilder.h"
00037 #include "PKIFReversePathState.h"
00038 #include "PKIFTrustRoot.h"
00039 #include "PKIX1Explicit88.h"
00040 #include "ToolkitUtils.h"
00041 #include <sstream>
00042 #include "PKIFDefaultScoring.h"
00043 
00044 #include "boost/numeric/conversion/cast.hpp"
00045 
00046 using boost::numeric_cast;
00047 using boost::bad_numeric_cast;
00048 
00049 
00050 #include <iterator>
00051 
00052 using namespace std;
00053 using namespace boost;
00054 
00063 void RemoveNotIssuedTo(CPKIFNamePtr& name, CPKIFCertificateNodeList& certList)
00064 {
00065     NotIssuedTo notIssuedTo;
00066     notIssuedTo.SetRHS(name);
00067     CPKIFCertificateNodeList::iterator end;
00068     end = remove_if(certList.begin(), certList.end(), notIssuedTo);
00069     certList.erase(end, certList.end());
00070 }
00079 void RemoveNotIssuedBy(CPKIFNamePtr& name, CPKIFCertificateNodeList& certList)
00080 {
00081     NotIssuedBy notIssuedBy;
00082     notIssuedBy.SetRHS(name);
00083     CPKIFCertificateNodeList::iterator end;
00084     end = remove_if(certList.begin(), certList.end(), notIssuedBy);
00085     certList.erase(end, certList.end());
00086 }
00087 
00088 //defined in Name.cpp
00089 bool RDNsMatch(
00091     CACX509V3RelativeDistinguishedName* lhs,
00093     CACX509V3RelativeDistinguishedName* rhs);
00094 
00095 
00102 class NameAndKeyNodeMatch
00103 {
00104 public:
00105     bool operator()(const CPKIFNameAndKeyWithScorePtr& t);
00106 
00114     void SetRHS(const IPKIFNameAndKeyPtr& rhs) {m_rhs = rhs;}
00115 private:
00116     IPKIFNameAndKeyPtr m_rhs;
00117 };
00118 
00127 bool NameAndKeyNodeMatch::operator()(const CPKIFNameAndKeyWithScorePtr& t)
00128 {
00129     return *t == *m_rhs;        
00130 }
00131 
00132 #define NAME_MATCHES_TARGET_ISSUER          5000
00133 #define ISSUED_BY_TRUST_ROOT                5000
00134 #define ISSUED_BY_CERT_IN_CACHE             500
00135 #define BASIC_CONSTRAINTS_PRESENT_AND_SET   75
00136 #define VAL_PERIOD_OK                       75
00137 #define ALGS_MATCH                          100
00138 #define KEY_IDS_MATCH                       6000 
00139 #define NOT_SELF_ISSUED                     50
00140 #define NOT_SELF_SIGNED                     50
00141 
00142 //added the following - 7/21/2005
00143 #define HAS_AT_ONE_POLICY                   25
00144 #define MATCH_POLICY_WITH_PREV_CERT         25
00145 #define MATCH_POLICY_WITH_SETTINGS          25
00146 
00155 bool scoreCompare(
00157     const CPKIFNameAndKeyWithScorePtr& lhs, 
00159     const CPKIFNameAndKeyWithScorePtr& rhs)
00160 {
00161     LOG_STRING_DEBUG("scoreCompare(const CPKIFCertificateNodeEntryPtr& lhs, const CPKIFCertificateNodeEntryPtr& rhs)", TOOLKIT_PATH_MISC, 0, NULL);
00162 
00163     int rhsScore = rhs->GetScore();
00164     int lhsScore = lhs->GetScore();
00165     return lhsScore > rhsScore;
00166 }
00167 
00176 int GetNumMatchingRdns(CPKIFNamePtr& name1, CPKIFNamePtr& name2)
00177 {
00178     CACASNWRAPPER_CREATE(CACX509V3Name, objPDU1);
00179     CPKIFBufferPtr name1Buf = name1->rawName();
00180     objPDU1.Decode(name1Buf->GetBuffer(), name1Buf->GetLength());
00181     
00182     CACASNWRAPPER_CREATE(CACX509V3Name, objPDU2);
00183     CPKIFBufferPtr name2Buf = name2->rawName();
00184     objPDU2.Decode(name2Buf->GetBuffer(), name2Buf->GetLength());
00185 
00186 
00187     DListNode* curLHS = objPDU1->u.rdnSequence->head;
00188     DListNode* curRHS = objPDU2->u.rdnSequence->head;
00189     unsigned int max = 0;
00190     if(objPDU1->u.rdnSequence->count > objPDU2->u.rdnSequence->count)
00191         max = objPDU2->u.rdnSequence->count;
00192     else
00193         max = objPDU1->u.rdnSequence->count;
00194 
00195     for(unsigned int ii = 0; ii < max; ++ii)
00196     {
00197         //added 8/26/2004
00198         ASN1OpenType* lhsP = (ASN1OpenType*)curLHS->data;
00199         ASN1OpenType* rhsP = (ASN1OpenType*)curRHS->data;
00200         if(lhsP->numocts != rhsP->numocts || 0 != memcmp(lhsP->data, rhsP->data, rhsP->numocts))
00201         {
00202             //parse and compare if binary equality fails - 8/26/2004
00203             CACASNWRAPPER_CREATE(CACX509V3RelativeDistinguishedName, tmpPDULHS);
00204             CACX509V3RelativeDistinguishedName* lhs = tmpPDULHS.Decode(*lhsP);
00205 
00206             CACASNWRAPPER_CREATE(CACX509V3RelativeDistinguishedName, tmpPDURHS);
00207             CACX509V3RelativeDistinguishedName* rhs = tmpPDURHS.Decode(*rhsP);
00208 
00209             if(!RDNsMatch(lhs, rhs))
00210                 return ii;
00211         }
00212         curLHS = curLHS->next; 
00213         curRHS = curRHS->next;
00214     }
00215     return max;
00216 }
00217 
00227 void ScoreAndSortNodes(
00229     CPKIFNameAndKeyWithScoreListPtr& listToSort, 
00231     CPKIFCertificatePtr& targetCert, 
00233     IPKIFNameAndKeyPtr& issuerNameAndKey, 
00235     CPKIFPathSettingsPtr& settings, 
00237     bool toToSortContainsTrustAnchors)
00238 {
00239     CPKIFNamePtr targetIssuerName = targetCert->Issuer();
00240     CPKIFPolicyInformationListPtr initPolSet;
00241     settings->GetInitialPolicySet(initPolSet);
00242 
00243     CPKIFNamePtr curCertIssuerName;
00244     if(issuerNameAndKey != (IPKIFNameAndKey*)NULL)
00245         curCertIssuerName = issuerNameAndKey->GetSubjectName();
00246 
00247     CPKIFNameAndKeyWithScoreList::iterator pos;
00248     CPKIFNameAndKeyWithScoreList::iterator end = listToSort->end();
00249     for(pos = listToSort->begin(); pos != end; ++pos)
00250     {
00251         (*pos)->ClearScore();
00252         IPKIFNameAndKeyPtr curNameAndKey = (*pos)->GetNameAndKey();
00253 
00254         //if subject name matches target issuer name
00255         if(*targetIssuerName == *curNameAndKey->GetSubjectName())
00256             (*pos)->AddToScore(NAME_MATCHES_TARGET_ISSUER);
00257 
00258 
00259         CPKIFNamePtr tmpName = curNameAndKey->GetSubjectName();
00260         int namePoints = 1000 * GetNumMatchingRdns(targetIssuerName, tmpName);
00261         (*pos)->AddToScore(namePoints);
00262 
00263         if(curCertIssuerName != (CPKIFName*)NULL && !(*curCertIssuerName == *curNameAndKey->GetIssuerName()))
00264         {
00265             (*pos)->ClearScore();
00266             continue;   //no point further evaluating something for which name chaining fails
00267         }
00268 
00269         //some checks are only appropriate if the item is a certificate
00270         CPKIFCertificatePtr curCert = dynamic_pointer_cast<CPKIFCertificate, IPKIFNameAndKey>(curNameAndKey);
00271         if(curCert != (CPKIFCertificate*)NULL)
00272         {
00273             CPKIFBasicConstraintsPtr basicConstraints = curCert->GetExtension<CPKIFBasicConstraints>();
00274             bool isCA = false;
00275             if(basicConstraints != (CPKIFBasicConstraints*)NULL)
00276             {
00277                 if(basicConstraints->isCA())
00278                     (*pos)->AddToScore(BASIC_CONSTRAINTS_PRESENT_AND_SET);
00279                 else
00280                 {
00281                     (*pos)->ClearScore();
00282                     continue;
00283                 }
00284             }       
00285 
00286             //XXX***add more sorting logic here (steal from forward builder
00287         }
00288     }
00289 
00290     sort(listToSort->begin(), listToSort->end(), scoreCompare);
00291 
00292 #ifdef _DEBUG
00293     IPKIFNameAndKeyPtr frontNK = listToSort->front()->GetNameAndKey();
00294     int score = listToSort->front()->GetScore();
00295     CPKIFNamePtr frontNKName = frontNK->GetSubjectName();
00296     const char* frontNKNameStr = frontNKName->ToString();
00297 #endif
00298 }
00299 
00301 struct CPKIFReversiblePathBuilderImpl 
00302 {
00303     PathBuildingDirection m_pbd;
00304     CPKIFReversiblePathBuilder *m_parent;
00305     std::vector<CPKIFNameAndKeyWithScoreList> m_previouslyTriedPaths;
00306     bool TriedBefore(CPKIFNameAndKeyWithScoreList& builtPathNK);
00307 
00308     //function that builds a table or grows a table by extending rows with additional sources
00309     bool BuildOrGrowTable(CPKIFReversePathStatePtr& reverseState);
00310 
00311     //function that checks for paths in the current table of certs
00312     bool CheckAlternatives(CPKIFCertificatePath& path, CPKIFReversePathStatePtr& reverseState);
00313 
00314     //function that removes the current row nearest the root
00315     void PuntTopRow(CPKIFReversePathStatePtr& reverseState);
00316 
00317     bool GrowRows(CPKIFReversePathStatePtr& reverseState);
00318 
00319     //function that removes certs from a list that would create a loop in the current path
00320     void RemoveLoopMakers(CPKIFCertificateNodeList& certList, CPKIFReversePathStatePtr& reverseState);
00321 
00322     void PrepareState_Forward(CPKIFReversePathStatePtr& reverseState, CPKIFCertificatePath& path);
00323     void PrepareState_Reverse(CPKIFReversePathStatePtr& reverseState, CPKIFCertificatePath& path);
00324     void CreateState(CPKIFCertificatePath& path, PathBuildingDirection pbd);
00325     void CheckInputs(CPKIFCertificatePath& path);
00326     bool TargetIsTrustAnchor(CPKIFCertificatePtr& cert);
00327     IPKIFNameAndKeyPtr GetCurrentCert(CPKIFReversePathStatePtr& reverseState);
00328 
00329     void GetCerts(CPKIFCertificateSourceListPtr& curSourceList, CPKIFCertificateNodeList& certNodeList, CPKIFReversePathStatePtr& reverseState);
00330     void SortAndSaveLists(CPKIFReversePathStatePtr& reverseState, CPKIFNameAndKeyWithScoreListPtr& newList, CPKIFCertificateSourceListPtr& sources);
00331     void RemoveExtraneous(CPKIFCertificateNodeList& certList, CPKIFReversePathStatePtr& reverseState);
00332 };
00333 
00341 void CPKIFReversiblePathBuilderImpl::SortAndSaveLists(CPKIFReversePathStatePtr& reverseState, 
00342                                                   CPKIFNameAndKeyWithScoreListPtr& newList, CPKIFCertificateSourceListPtr& sources)
00343 {
00344     //sort sources
00345 
00346     //first off, get some cert from sources if newList is empty
00347     if(newList->empty())
00348     {
00349         CPKIFCertificateNodeList certNodeList;
00350         GetCerts(sources, certNodeList, reverseState);
00351 
00352         //remove any loops from the list, if there is a list
00353         RemoveLoopMakers(certNodeList, reverseState);
00354         RemoveExtraneous(certNodeList, reverseState);
00355 
00356         if(!certNodeList.empty())
00357         {
00358             //if there are still certs in the list, then add them to the corresponding row
00359             //in m_table, provided the cert is not already in the list
00360 
00361             CPKIFCertificateNodeList::iterator cnlPos;
00362             CPKIFCertificateNodeList::iterator cnlEnd = certNodeList.end();
00363             for(cnlPos = certNodeList.begin(); cnlPos != cnlEnd; ++cnlPos)
00364             {
00365                 IPKIFNameAndKeyPtr cnlCertAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>((*cnlPos)->GetCert());
00366                 CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(cnlCertAsNameAndKey));
00367                 newList->push_back(newNode);
00368             }
00369         }
00370     }
00371 
00372     //if we don't have any certs, simply return and let PuntTopRow take over
00373     if(newList->empty())
00374         return;
00375 
00376     if(PBD_FORWARD == reverseState->m_direction)
00377     {
00378         //TODO: 
00379         //  - sort the name and key list for forward direction building
00380         IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
00381         IPKIFCertRepository* iCert = m_parent->GetMediatorFromParent<IPKIFCertRepository>();
00382         IPKIFNameAndKeyPtr curCertAsNameAndKey = GetCurrentCert(reverseState);
00383         CPKIFCertificatePtr curCert = dynamic_pointer_cast<CPKIFCertificate, IPKIFNameAndKey>(curCertAsNameAndKey);
00384 
00385         CPKIFDefaultScoring s;
00386         int nCAsBelow = 0;
00387         try {
00388             nCAsBelow = boost::numeric_cast<int,size_t>(reverseState->m_table.size() - 1);
00389         }catch(std::exception &e){
00390             RAISE_PATH_EXCEPTION(e.what(), m_parent->thisComponent, COMMON_INVALID_INPUT, this)
00391         }
00392         s.ScoreAndSortNodes(newList, curCert, reverseState->m_pathSettings, iTrust, nCAsBelow ,iCert);
00393         
00394         reverseState->m_table.push_back(newList);
00395         reverseState->m_sourceTable.push_back(sources);
00396 
00397 #ifdef _DEBUG
00398         vector<string> v;
00399         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzpos;
00400         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzend = reverseState->m_table.end();
00401         for(zzzpos = reverseState->m_table.begin(); zzzpos != zzzend; ++zzzpos)
00402         {
00403             v.push_back((*zzzpos)->front()->GetNameAndKey()->GetSubjectName()->ToString());
00404             v.push_back((*zzzpos)->front()->GetNameAndKey()->GetIssuerName()->ToString());
00405         }
00406 #endif
00407     }
00408     else
00409     {
00410         //TODO: 
00411         //  - sort the name and key list for reverse direction building
00412         reverseState->m_table.insert(reverseState->m_table.begin(), newList);
00413         reverseState->m_sourceTable.insert(reverseState->m_sourceTable.begin(), sources);
00414     }
00415 }
00416 
00425 bool CPKIFReversiblePathBuilderImpl::TargetIsTrustAnchor(CPKIFCertificatePtr& cert)
00426 {
00427     IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
00428 
00429     IPKIFTrustAnchorList tmpRootList;
00430     iTrust->GetTrustRoots(cert->GetSubjectName(), tmpRootList);
00431     if(!tmpRootList.empty())
00432     {
00433         //iterate over the roots and see if any match the target
00434         IPKIFTrustAnchorList::iterator rootPos;
00435         IPKIFTrustAnchorList::iterator rootEnd = tmpRootList.end();
00436         for(rootPos = tmpRootList.begin(); rootPos != rootEnd; ++rootPos)
00437         {
00438             IPKIFNameAndKeyPtr taNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, IPKIFTrustAnchor>(*rootPos);
00439             IPKIFNameAndKeyPtr certNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>(cert);
00440             if(*certNameAndKey == *taNameAndKey)
00441                 return true;
00442         }
00443     }
00444 
00445     return false;
00446 }
00447 
00456 void CPKIFReversiblePathBuilderImpl::PrepareState_Forward(CPKIFReversePathStatePtr& reverseState, CPKIFCertificatePath& path)
00457 {
00458     reverseState->m_direction = PBD_FORWARD;
00459 
00460     IPKIFNameAndKeyPtr targetCertAsNameAndKey;
00461     CPKIFCertificatePtr targetCert;
00462     path.GetTarget(targetCert);
00463     targetCertAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>(targetCert);
00464 
00465     reverseState->m_targetCert = targetCert;
00466     reverseState->m_targetCertAsNameAndKey = targetCertAsNameAndKey;
00467 
00468     CPKIFCertificateSourceListPtr emptySourceList(new CPKIFCertificateSourceList);
00469     CPKIFNameAndKeyWithScoreListPtr newList(new CPKIFNameAndKeyWithScoreList);
00470     CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(reverseState->m_targetCertAsNameAndKey));
00471     newList->push_back(newNode);
00472 
00473     reverseState->m_table.push_back(newList);
00474     reverseState->m_sourceTable.push_back(emptySourceList);
00475 
00476 #ifdef _DEBUG
00477     vector<string> v;
00478     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzpos;
00479     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzend = reverseState->m_table.end();
00480     for(zzzpos = reverseState->m_table.begin(); zzzpos != zzzend; ++zzzpos)
00481     {
00482         v.push_back((*zzzpos)->front()->GetNameAndKey()->GetSubjectName()->ToString());
00483         v.push_back((*zzzpos)->front()->GetNameAndKey()->GetIssuerName()->ToString());
00484     }
00485 #endif
00486 }
00487 
00496 void CPKIFReversiblePathBuilderImpl::PrepareState_Reverse(CPKIFReversePathStatePtr& reverseState, CPKIFCertificatePath& path)
00497 {
00498     reverseState->m_direction = PBD_REVERSE;
00499 
00500     //get the target certificate and save a pointer to it and to its IPKIFNameAndKey interface in reverseState
00501     IPKIFNameAndKeyPtr targetCertAsNameAndKey;
00502     CPKIFCertificatePtr targetCert;
00503     path.GetTarget(targetCert);
00504     targetCertAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>(targetCert);
00505 
00506     reverseState->m_targetCert = targetCert;
00507     reverseState->m_targetCertAsNameAndKey = targetCertAsNameAndKey;
00508 
00509     //since we are building in reverse, we will get a list of all trust anchors.  
00510     CPKIFNamePtr emptyName;
00511     IPKIFTrustAnchorList tl;
00512     IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
00513     iTrust->GetTrustRoots(emptyName, tl);
00514 
00515     //create a CPKIFNameAndKeyWithScoreList and push the trust anchors into it.  then sort the list
00516     //and push it into the table.
00517     CPKIFNameAndKeyWithScoreListPtr scoreList(new CPKIFNameAndKeyWithScoreList);    
00518 
00519     IPKIFTrustAnchorList::iterator pos;
00520     IPKIFTrustAnchorList::iterator end = tl.end();
00521     for(pos = tl.begin(); pos != end; ++pos)
00522     {
00523         IPKIFNameAndKeyPtr curTA = dynamic_pointer_cast<IPKIFNameAndKey, IPKIFTrustAnchor>(*pos);
00524 
00525         CPKIFNameAndKeyWithScorePtr tmp(new CPKIFNameAndKeyWithScore(curTA));
00526         scoreList->push_back(tmp);
00527     }
00528 
00529     IPKIFNameAndKeyPtr emptyNameAndKey;
00530     ScoreAndSortNodes(scoreList, targetCert, emptyNameAndKey, reverseState->m_pathSettings, true);
00531 
00532     //there is not a node for additional root sources, so we simply push an empty row there
00533     CPKIFCertificateSourceListPtr sourceList(new CPKIFCertificateSourceList); //NULL indicates time to remove, need empty list
00534 
00535     reverseState->m_table.push_back(scoreList);
00536     reverseState->m_sourceTable.push_back(sourceList);
00537 }
00538 
00547 void CPKIFReversiblePathBuilderImpl::CreateState(CPKIFCertificatePath& path, PathBuildingDirection pbd)
00548 {
00549     //allocate the new state... (throw bad_alloc)
00550     CPKIFReversePathStatePtr reverseState(new CPKIFReversePathState);   
00551 
00552     reverseState->m_sources = LOCAL;
00553     reverseState->m_bTableIsComplete = false;
00554     reverseState->m_bBuildStarted = false;
00555 
00556     //and builder statistics (throw bad_alloc)
00557     CPKIFBuilderStatisticsPtr bs(new CPKIFBuilderStatistics);
00558     path.SetBuilderStats(bs);
00559 
00560     //store it in the path
00561     CPKIFCertificatePathStatePtr tmpState(reverseState);
00562     path.SetState(tmpState);
00563 
00564     path.GetPathSettings(reverseState->m_pathSettings);
00565 
00566     if(PBD_FORWARD == pbd)
00567         PrepareState_Forward(reverseState, path);
00568     else
00569         PrepareState_Reverse(reverseState, path);
00570 }
00571 
00572 
00582 void CPKIFReversiblePathBuilderImpl::CheckInputs(CPKIFCertificatePath& path)
00583 {
00584     LOG_STRING_DEBUG("CPKIFReversiblePathBuilder::CreateInputs(CPKIFCertificatePath& path)", m_parent->thisComponent, 0, this);
00585 
00586     //we need to have at least an IPKIFTrustCache interface and an IPKIFCertRepository interface
00587     IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
00588     if(NULL == iTrust)
00589         RAISE_PATH_EXCEPTION("IPKIFTrustCache interface not available.", m_parent->thisComponent, COMMON_MEDIATOR_MISSING, this)
00590 
00591     IPKIFCertRepository* iCert = m_parent->GetMediatorFromParent<IPKIFCertRepository>();
00592     if(NULL == iCert)
00593         RAISE_PATH_EXCEPTION("IPKIFCertRepository interface not available.", m_parent->thisComponent, COMMON_MEDIATOR_MISSING, this)
00594 
00595     //require that settings be non-NULL
00596     CPKIFPathSettingsPtr settings;
00597     path.GetPathSettings(settings);
00598     if(settings == (CPKIFPathSettings*)NULL)
00599         RAISE_PATH_EXCEPTION("Path parameter contained NULL path settings.", m_parent->thisComponent, COMMON_INVALID_INPUT, this)
00600 
00601     CPKIFCertificatePtr curCert;
00602     path.GetTarget(curCert);
00603     if(curCert == (CPKIFCertificate*)NULL)
00604         RAISE_PATH_EXCEPTION("The path parameter did not specify a target certificate.", m_parent->thisComponent, COMMON_INVALID_INPUT, this)
00605 }
00606 
00614 size_t GetTableSize(vector<CPKIFNameAndKeyWithScoreListPtr>& v)
00615 {
00616     size_t rowSum = 0;
00617     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator pos;
00618     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator end = v.end();
00619     for(pos = v.begin(); pos != end; ++pos)
00620         rowSum += (*pos)->size();
00621 
00622     return rowSum;
00623 }
00624 
00633 void CPKIFReversiblePathBuilderImpl::GetCerts(CPKIFCertificateSourceListPtr& curSourceList, CPKIFCertificateNodeList& certNodeList, CPKIFReversePathStatePtr& reverseState)
00634 {
00635     do
00636     {
00637         //get the source at the back of the source list, then remove it from the list
00638         CPKIFCertificateSourcePtr curSource = curSourceList->back();
00639         curSourceList->pop_back();
00640 
00641         //retrieve some certs, if possible
00642         curSource->GetCertificates(certNodeList, reverseState->m_direction);
00643 
00644         //loop until we either get some certs or run out of sources in this row
00645     }while(certNodeList.empty() && !curSourceList->empty());
00646 
00647 #ifdef _DEBUG
00648     vector<string> v;
00649     CPKIFCertificateNodeList::iterator pos;
00650     CPKIFCertificateNodeList::iterator end = certNodeList.end();
00651     for(pos = certNodeList.begin(); pos != end; ++pos)
00652     {
00653         v.push_back((*pos)->GetCert()->Subject()->ToString());
00654         v.push_back((*pos)->GetCert()->Issuer()->ToString());
00655     }
00656 #endif
00657 }
00658 
00667 bool CPKIFReversiblePathBuilderImpl::GrowRows(CPKIFReversePathStatePtr& reverseState)
00668 {
00669     bool rv = false;
00670     int numRows = 0;
00671     try 
00672     {
00673         numRows = numeric_cast<int>(reverseState->m_table.size());
00674     }
00675     catch(bad_numeric_cast &) 
00676     {
00677         throw CPKIFException(TOOLKIT_PATH, COMMON_INVALID_INPUT, "Table size is an impossibly long number.");
00678     }
00679     
00680     assert((reverseState->m_table.empty() &&reverseState->m_sourceTable.empty()) || (reverseState->m_table.size() == reverseState->m_sourceTable.size()));
00681 
00682     int ii = PBD_FORWARD == reverseState->m_direction? numRows-2 : 0;
00683     int terminator = PBD_FORWARD == reverseState->m_direction? 0 : numRows-2;
00684     if(ii < 0 || terminator < 0)
00685     {
00686         ii = 0; terminator = 0 ; //this is necessary when only row is root row
00687     }
00688     for(; (PBD_FORWARD == reverseState->m_direction && ii >= terminator) || (PBD_REVERSE == reverseState->m_direction && ii <= terminator); 
00689         PBD_FORWARD == reverseState->m_direction? --ii : ++ii)
00690     {
00691         CPKIFNameAndKeyWithScoreListPtr curNameAndKeyList = reverseState->m_table[ii];
00692         CPKIFCertificateSourceListPtr curSourceList = reverseState->m_sourceTable[ii];
00693         if(curSourceList == (CPKIFCertificateSourceList*)NULL || curSourceList->empty())
00694             continue;
00695 
00696         CPKIFCertificateNodeList certNodeList;
00697         GetCerts(curSourceList, certNodeList, reverseState);
00698 
00699         //remove any loops from the list, if there is a list
00700         RemoveLoopMakers(certNodeList, reverseState);
00701         RemoveExtraneous(certNodeList, reverseState);
00702 
00703         if(!certNodeList.empty())
00704         {
00705             //if there are still certs in the list, then add them to the corresponding row
00706             //in m_table, provided the cert is not already in the list
00707 
00708             CPKIFCertificateNodeList::iterator cnlPos;
00709             CPKIFCertificateNodeList::iterator cnlEnd = certNodeList.end();
00710             for(cnlPos = certNodeList.begin(); cnlPos != cnlEnd; ++cnlPos)
00711             {
00712                 IPKIFNameAndKeyPtr cnlCertAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>((*cnlPos)->GetCert());
00713                 CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(cnlCertAsNameAndKey));
00714                 GottaMatch<CPKIFNameAndKeyWithScorePtr> gm;
00715                 gm.SetRHS(newNode);
00716                 if(curNameAndKeyList->end() == find_if(curNameAndKeyList->begin(), curNameAndKeyList->end(), gm))
00717                 {
00718                     curNameAndKeyList->push_back(newNode);
00719                     rv = true;
00720                 }
00721             }
00722         }
00723 
00724         if(curSourceList->empty() && curNameAndKeyList->empty())
00725         {
00726             CPKIFCertificateSourceListPtr emptyList;
00727             reverseState->m_sourceTable[ii] = emptyList;
00728         }
00729     }
00730 
00731     return rv;
00732 }
00733 
00742 void CPKIFReversiblePathBuilderImpl::PuntTopRow(
00744     CPKIFReversePathStatePtr& reverseState)
00745 
00746 {
00747 #ifdef _DEBUG
00748             vector<string> v;
00749             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzpos;
00750             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzend = reverseState->m_table.end();
00751             for(zzzpos = reverseState->m_table.begin(); zzzpos != zzzend; ++zzzpos)
00752             {
00753                 v.push_back((*zzzpos)->front()->GetNameAndKey()->GetSubjectName()->ToString());
00754                 v.push_back((*zzzpos)->front()->GetNameAndKey()->GetIssuerName()->ToString());
00755             }
00756 #endif
00757 
00758     CPKIFNamePtr nameOfIssuerToDiscard;
00759 
00760     //We only care if GrowRow changes the current cert.  If it doesn't,
00761     //then we are still removing this row
00762     IPKIFNameAndKeyPtr preGrowCur = GetCurrentCert(reverseState);
00763 
00764     bool bAddedNewStuff = GrowRows(reverseState);
00765 
00766     IPKIFNameAndKeyPtr postGrowCur = GetCurrentCert(reverseState);
00767     if((preGrowCur == (IPKIFNameAndKey*)NULL && postGrowCur != (IPKIFNameAndKey*)NULL) || 
00768         ((preGrowCur != (IPKIFNameAndKey*)NULL && postGrowCur != (IPKIFNameAndKey*)NULL) && !(*preGrowCur == *postGrowCur)))
00769         return;
00770 
00771     if(PBD_FORWARD == reverseState->m_direction)
00772     {
00773         int size = 0;
00774         try 
00775         {
00776             size = numeric_cast<int>(reverseState->m_table.size());
00777         }
00778         catch(bad_numeric_cast &) 
00779         {
00780             throw CPKIFException(TOOLKIT_PATH, COMMON_INVALID_INPUT, "Table size is an impossibly long number.");
00781         }
00782 
00783         //the top of the table is the end of the vector - iterate in reverse
00784         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator pos = reverseState->m_table.rbegin();
00785         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator end = reverseState->m_table.rend();
00786         for(int ii = size - 1; pos != end - 1; ++pos, --ii) //end - 1 to avoid thwacking the target row
00787         {
00788             if((*pos)->empty())
00789                 continue;
00790 
00791             //get the name of the issuer at the front of the current row
00792             if(nameOfIssuerToDiscard == (CPKIFName*)NULL)
00793                 nameOfIssuerToDiscard = (*pos)->front()->GetNameAndKey()->GetIssuerName();
00794 
00795             CPKIFNamePtr tmpName = (*pos)->front()->GetNameAndKey()->GetSubjectName();
00796 
00797     #ifdef _DEBUG
00798             const char* curCertIssuerString = nameOfIssuerToDiscard->ToString();
00799             const char* curCertSubjectString = tmpName->ToString();
00800             size_t size = (*pos)->size();
00801     #endif
00802 
00803             RemoveAllIssuedBy(*pos, nameOfIssuerToDiscard);
00804 
00805     #ifdef _DEBUG
00806             size = (*pos)->size();
00807     #endif
00808 
00809             //update the previous name to the name of the front cert of the current row
00810             //it will be used to thin the next row if this row went empty on the above
00811             //remove call
00812             nameOfIssuerToDiscard = tmpName;
00813 
00814             //if the current row is not empty after the above remove call then there's still hope
00815             if(!(*pos)->empty())
00816                 break;
00817             else
00818             {
00819                 CPKIFCertificateSourceListPtr emptySourceList;
00820                 reverseState->m_sourceTable[ii] = emptySourceList;
00821                 reverseState->m_bTableIsComplete = false;
00822             }
00823         }
00824     }
00825     else
00826     {
00827         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator pos = reverseState->m_table.begin();
00828         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator end = reverseState->m_table.end();
00829         if(reverseState->m_bTableIsComplete)
00830         {
00831             (*pos)->clear();//remove target row
00832             ++pos;
00833         }
00834 
00835         int distanceLen = 0;
00836         try 
00837         {
00838             distanceLen = numeric_cast<int>(distance(reverseState->m_table.begin(), pos));
00839         }
00840         catch(bad_numeric_cast &) 
00841         {
00842             throw CPKIFException(TOOLKIT_PATH, COMMON_INVALID_INPUT, "Distance is an impossibly long number.");
00843         }
00844 
00845 
00846         for(int ii = distanceLen; pos != end; ++pos, ++ii)
00847         {
00848             if((*pos)->empty())
00849                 continue;
00850 
00851             //get the name of the issuer at the front of the current row
00852             if(nameOfIssuerToDiscard == (CPKIFName*)NULL && pos != reverseState->m_table.begin())
00853                 nameOfIssuerToDiscard = (*pos)->front()->GetNameAndKey()->GetSubjectName();
00854             else if(nameOfIssuerToDiscard == (CPKIFName*)NULL)
00855                 nameOfIssuerToDiscard = (*pos)->front()->GetNameAndKey()->GetIssuerName();
00856 
00857             CPKIFNamePtr tmpName = (*pos)->front()->GetNameAndKey()->GetIssuerName();
00858 
00859     #ifdef _DEBUG
00860             const char* curCertIssuerString = nameOfIssuerToDiscard->ToString();
00861             const char* curCertSubjectString = tmpName->ToString();
00862             size_t size = (*pos)->size();
00863     #endif
00864 
00865             if(pos != reverseState->m_table.begin())
00866                 RemoveAllIssuedTo(*pos, nameOfIssuerToDiscard);
00867             else
00868                 RemoveAllIssuedBy(*pos, nameOfIssuerToDiscard);
00869 
00870     #ifdef _DEBUG
00871             size = (*pos)->size();
00872     #endif
00873 
00874             //update the previous name to the name of the front cert of the current row
00875             //it will be used to thin the next row if this row went empty on the above
00876             //remove call
00877             nameOfIssuerToDiscard = tmpName;
00878 
00879             //if the current row is not empty after the above remove call then there's still hope
00880             if(!(*pos)->empty())
00881                 break;
00882             else
00883             {
00884                 CPKIFCertificateSourceListPtr nullSourceList;
00885                 reverseState->m_sourceTable[ii] = nullSourceList;
00886                 reverseState->m_bTableIsComplete = false;
00887             }
00888         }
00889     }
00890 
00891     //state preservation (ideally, this would not be necessary as it indicates something else is wrong)
00892     {
00893         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator nkPos;
00894         vector<CPKIFNameAndKeyWithScoreListPtr>::iterator nkEnd = reverseState->m_table.end();
00895         int ii = 0;
00896         CPKIFCertificateSourceListPtr nullSourceList;
00897         for(nkPos = reverseState->m_table.begin(); nkPos != nkEnd; ++nkPos, ++ii)
00898         {
00899             if((*nkPos)->empty())
00900                 reverseState->m_sourceTable[ii] = nullSourceList;
00901         }
00902     }
00903 
00904     //look at each row in the table and delete those that are empty
00905     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator newEnd = remove_if(reverseState->m_table.begin(), reverseState->m_table.end(), IsEmptyNameAndKey);
00906     reverseState->m_table.erase(newEnd, reverseState->m_table.end());
00907 
00908     vector<CPKIFCertificateSourceListPtr>::iterator newEndSourceList = remove_if(reverseState->m_sourceTable.begin(), reverseState->m_sourceTable.end(), IsNullCertificateSourceList);
00909     reverseState->m_sourceTable.erase(newEndSourceList, reverseState->m_sourceTable.end());
00910 }
00911 
00919 void CPKIFReversiblePathBuilderImpl::RemoveLoopMakers(
00920     CPKIFCertificateNodeList& certList, 
00921     CPKIFReversePathStatePtr& reverseState)
00922 {
00923     //if the table is empty or certList is empty then there are no "loop makers" - return immediately
00924     if(reverseState->m_table.empty() || certList.empty())
00925         return;
00926 
00927     //otherwise - iterate over the table and build a partial path taking the frontmost
00928     //node from each row in the table (It'd be a good idea to maintain a running partial
00929     //path so we can avoid repeated calls to setup and tear down the partial path list)
00930     CPKIFNameAndKeyWithScoreList builtPath;
00931     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator pos = reverseState->m_table.begin();
00932     vector<CPKIFNameAndKeyWithScoreListPtr>::iterator end = reverseState->m_table.end();
00933     for(; pos != end; ++pos)
00934     {
00935         if(!(*pos)->empty())    //should only ever occur on first row in cases where no locals existed but a remote did
00936         {
00937             IPKIFNameAndKeyPtr tmpNameAndKey = (*pos)->front()->GetNameAndKey();
00938             CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(tmpNameAndKey));
00939             builtPath.push_back(newNode);
00940         }
00941     }
00942 
00943 #ifdef _DEBUG
00944     size_t size = certList.size();
00945 #endif
00946 
00947     //prepare a NodeInNodeList predicate object with the partial path that was just built
00948     NodeInNodeList n;
00949     n.SetNodeList(&builtPath);
00950 
00951     //invoke the remove_if alg using the NodeInNodeList object (i.e. iterate over
00952     //certList and move all entries that are present in the builtPath to the end 
00953     //of the list so they can be removed by the call to erase).
00954     CPKIFCertificateNodeList::iterator newEnd = remove_if(certList.begin(), certList.end(), n);
00955     certList.erase(newEnd, certList.end());
00956 
00957 #ifdef _DEBUG
00958     size = certList.size();
00959 #endif
00960 }
00961 
00970 IPKIFNameAndKeyPtr CPKIFReversiblePathBuilderImpl::GetCurrentCert(CPKIFReversePathStatePtr& reverseState)
00971 {
00972     IPKIFNameAndKeyPtr empty;
00973     if(reverseState->m_table.empty())
00974         return empty;
00975 
00976     if(PBD_FORWARD == reverseState->m_direction)
00977     {
00978         //building towards the trust anchor, so current focal point is the front of the list
00979         //at the back of the vector.
00980         if(reverseState->m_table.back()->empty())
00981             return empty;
00982         else
00983             return reverseState->m_table.back()->front()->GetNameAndKey();
00984     }
00985     else
00986     {
00987         //building towards the target, so current focal point is the front of the list at the
00988         //front of the vector.
00989         if(reverseState->m_table.front()->empty())
00990             return empty;
00991         else
00992             return reverseState->m_table.front()->front()->GetNameAndKey();
00993     }
00994 }
00995 
01004 bool IsSelfSigned(CPKIFCertificateNodeEntryPtr& certNode)
01005 {
01006     if(certNode == (CPKIFCertificateNodeEntry*)NULL)
01007         return false;
01008 
01009     CPKIFCertificatePtr cert = certNode->GetCert();
01010     return cert->IsSelfSigned();
01011 }
01012 
01020 void CPKIFReversiblePathBuilderImpl::RemoveExtraneous(CPKIFCertificateNodeList& certList, CPKIFReversePathStatePtr& reverseState)
01021 {
01022     if(certList.empty()) //nothing to do
01023         return;
01024 
01025     if(PBD_FORWARD == reverseState->m_direction)
01026     {
01027         CPKIFNamePtr tmpName = reverseState->m_table.back()->front()->GetNameAndKey()->GetIssuerName();
01028         RemoveNotIssuedTo(tmpName, certList);
01029     }
01030     else //PBD_REVERSE
01031     {
01032         //building from trust anchor to target, so the new list must feature certificates that were issued
01033         //by the current node from the table
01034         if(!reverseState->m_table.front()->empty())
01035         {
01036             CPKIFNamePtr tmpName = reverseState->m_table.front()->front()->GetNameAndKey()->GetSubjectName();
01037             RemoveNotIssuedBy(tmpName, certList);
01038         }
01039         //since this is not the root row, self-signed certs need not apply
01040         CPKIFCertificateNodeList::iterator end;
01041         end = remove_if(certList.begin(), certList.end(), IsSelfSigned);
01042         certList.erase(end, certList.end());
01043 
01044         //we do not need copies of certs in the list
01045         CPKIFCertificateNodeList listCopy;
01046 
01047         CPKIFCertificateNodeList::iterator clpos;
01048         CPKIFCertificateNodeList::iterator clend = certList.end();
01049         for(clpos = certList.begin(); clpos != clend; ++clpos)
01050         {
01051             GottaMatch<CPKIFCertificateNodeEntryPtr> gm;
01052             gm.SetRHS(*clpos);
01053             if(listCopy.end() == find_if(listCopy.begin(), listCopy.end(), gm))
01054                 listCopy.push_back(*clpos);
01055         }
01056 
01057         certList.clear();
01058         copy(listCopy.begin(), listCopy.end(), back_inserter(certList));
01059     }
01060 }
01061 
01071 bool CPKIFReversiblePathBuilderImpl::BuildOrGrowTable(CPKIFReversePathStatePtr& reverseState)
01072 {
01073     //if the table is complete and we are able to extend a few rows, we can return true
01074     //early and let CheckAlternatives have another go at it.
01075     if(reverseState->m_bTableIsComplete && GrowRows(reverseState))
01076         return true;
01077     else if(reverseState->m_bBuildStarted)
01078     {
01079         //get rid of a row and continue trying
01080         PuntTopRow(reverseState);
01081     }
01082     else
01083     {
01084         //Without this, the PuntTopRow above was eliminating a cert from the top row when 
01085         //building backwards.  Without the PuntTopRow, we never terminate.
01086         reverseState->m_bBuildStarted = true;
01087     }
01088 
01089     //----------------------------------------------------------------------------------------------------
01090     //  COLLECT INTERFACES
01091     //----------------------------------------------------------------------------------------------------
01092     //query for the various interfaces we will need:
01093     //  need: IPKIFCertRepository, IPKIFTrustCache
01094     //  use (if present): IPKIFCertRepositoryUpdate, IPKIFCRLRepository
01095     IPKIFCertRepository* iCert = m_parent->GetMediatorFromParent<IPKIFCertRepository>();
01096     IPKIFTrustCache* iTrust = m_parent->GetMediatorFromParent<IPKIFTrustCache>();
01097     if(NULL == iCert || NULL == iTrust)
01098         throw CPKIFPathException(m_parent->thisComponent, COMMON_MEDIATOR_MISSING, "IPKIFCertRepository and/or IPKIFTrustCache are not available.");
01099 
01100     //the cert and CRL update interfaces can be absent (if it's present we'll use it)
01101     IPKIFCertRepositoryUpdate* iCertUpdate = m_parent->GetMediatorFromParent<IPKIFCertRepositoryUpdate>();
01102     IPKIFCRLRepository* iCRL = m_parent->GetMediatorFromParent<IPKIFCRLRepository>();
01103     IPKIFSupportsSynonymousCertSources* iCertSS = m_parent->GetMediatorFromParent<IPKIFSupportsSynonymousCertSources>();
01104 
01105 #ifdef _DEBUG
01106     const char* targetIssuerName = reverseState->m_targetCertAsNameAndKey->GetIssuerName()->ToString();
01107     const char* targetSubjectName = reverseState->m_targetCertAsNameAndKey->GetSubjectName()->ToString();
01108 #endif
01109 
01110     IPKIFTrustAnchorList trustRootList; //used when building in the forward direction
01111     IPKIFNameAndKeyPtr curCertAsNameAndKey = GetCurrentCert(reverseState);
01112     
01113     do
01114     {
01115         size_t tableSize = reverseState->m_table.size();
01116         CPKIFCertificateSourceList certSourceList;
01117         CPKIFCertificateNodeList certList;
01118 
01119 #ifdef _DEBUG
01120         const char* curCertIssuerString = curCertAsNameAndKey->GetIssuerName()->ToString();
01121         const char* curCertSubjectString = curCertAsNameAndKey->GetSubjectName()->ToString();
01122 #endif
01123 
01124         //if building in the forward direction, we need to check to see if the issuer
01125         //is a trust anchor at each hop
01126         if(PBD_FORWARD == reverseState->m_direction && 
01127             iTrust->GetTrustRoots(curCertAsNameAndKey->GetIssuerName(), trustRootList))
01128         {
01129             //if we found a trust anchor, copy it into a CPKIFNameAndKeyWithScoreList and return true
01130             CPKIFNameAndKeyWithScoreListPtr newList(new CPKIFNameAndKeyWithScoreList);
01131             IPKIFTrustAnchorList::iterator trPos;
01132             IPKIFTrustAnchorList::iterator trEnd = trustRootList.end();
01133             for(trPos = trustRootList.begin(); trPos != trEnd; ++trPos)
01134             {
01135                 IPKIFNameAndKeyPtr trPosAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, IPKIFTrustAnchor>(*trPos);
01136                 CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(trPosAsNameAndKey));
01137                 newList->push_back(newNode);
01138             }
01139             CPKIFCertificateSourceListPtr emptySourceList;
01140             reverseState->m_bTableIsComplete = true;
01141 
01142             reverseState->m_table.push_back(newList);
01143             reverseState->m_sourceTable.push_back(emptySourceList);
01144 
01145 #ifdef _DEBUG
01146             vector<string> v;
01147             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzpos;
01148             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator zzzend = reverseState->m_table.end();
01149             for(zzzpos = reverseState->m_table.begin(); zzzpos != zzzend; ++zzzpos)
01150             {
01151                 v.push_back((*zzzpos)->front()->GetNameAndKey()->GetSubjectName()->ToString());
01152                 v.push_back((*zzzpos)->front()->GetNameAndKey()->GetIssuerName()->ToString());
01153             }
01154 #endif
01155 
01156             return true;
01157         }
01158         else if(PBD_REVERSE == reverseState->m_direction &&
01159             *curCertAsNameAndKey->GetSubjectName() == *reverseState->m_targetCertAsNameAndKey->GetIssuerName())
01160         {
01161             //we're building backwards and have found one or more certs issued to the issuer of the target
01162             CPKIFNameAndKeyWithScoreListPtr newList(new CPKIFNameAndKeyWithScoreList);
01163             CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(reverseState->m_targetCertAsNameAndKey));
01164             newList->push_back(newNode);
01165 
01166             CPKIFCertificateSourceListPtr emptySourceList;
01167             reverseState->m_bTableIsComplete = true;
01168 
01169             reverseState->m_table.insert(reverseState->m_table.begin(),newList);
01170             reverseState->m_sourceTable.insert(reverseState->m_sourceTable.begin(), emptySourceList);
01171             return true;
01172         }
01173         else
01174         {
01175             //if reverse or not a trust anchor, grabbing from all sources with direction indicated by the state object
01176             CPKIFCertificatePtr curCert = dynamic_pointer_cast<CPKIFCertificate, IPKIFNameAndKey>(curCertAsNameAndKey);
01177             if(curCert == (CPKIFCertificate*)NULL)
01178             {
01179                 CPKIFTrustRootPtr tr = dynamic_pointer_cast<CPKIFTrustRoot, IPKIFNameAndKey>(curCertAsNameAndKey);
01180                 if(tr != (CPKIFTrustRoot*)NULL)
01181                     tr->GetCert(curCert);
01182             }
01183 
01184             if(curCert != (CPKIFCertificate*)NULL)
01185             {
01186                 iCertSS->GetCertificateSources(curCert, certSourceList, reverseState->m_direction);
01187             }
01188             else if(PBD_FORWARD == reverseState->m_direction)
01189                 iCert->GetCertificates(curCertAsNameAndKey->GetIssuerName(), certList, reverseState->m_sources);
01190             else
01191             {
01192                 CPKIFException e(m_parent->thisComponent, COMMON_INVALID_INPUT, "Reverse direction building from non-certificate trust anchors is not supported");
01193                 throw e;
01194             }
01195             
01196             if(certList.size() || certSourceList.size())
01197             {
01198                 //at this point, we've retrieved all we can for the current cert (though we may not have 
01199                 //retrieved them yet) and need to sort the list
01200 
01201                 CPKIFNameAndKeyWithScoreListPtr newList(new CPKIFNameAndKeyWithScoreList);
01202                 CPKIFCertificateNodeList::iterator cPos;
01203                 CPKIFCertificateNodeList::iterator cEnd = certList.end();
01204                 for(cPos = certList.begin(); cPos != cEnd; ++cPos)
01205                 {
01206                     CPKIFCertificatePtr cPosAsCert = (*cPos)->GetCert();
01207                     IPKIFNameAndKeyPtr cPosAsNameAndKey = dynamic_pointer_cast<IPKIFNameAndKey, CPKIFCertificate>(cPosAsCert);
01208                     CPKIFNameAndKeyWithScorePtr newNode(new CPKIFNameAndKeyWithScore(cPosAsNameAndKey));
01209                     newList->push_back(newNode);
01210                 }
01211 
01212                 CPKIFCertificateSourceListPtr newSourceList(new CPKIFCertificateSourceList);
01213                 copy(certSourceList.begin(), certSourceList.end(), back_inserter(*newSourceList));
01214 
01215                 SortAndSaveLists(reverseState, newList, newSourceList);
01216             }
01217 
01218             //need to remove any certs that create loops with the current table
01219             RemoveLoopMakers(certList, reverseState);
01220 
01221             RemoveExtraneous(certList, reverseState);
01222 
01223             //if the table did not grow
01224             if(reverseState->m_table.size() == tableSize)
01225             {
01226                 //this will either resolve a remote source that was just identified (if no
01227                 //local sources were found) or punt the row
01228                 PuntTopRow(reverseState);
01229             }
01230         }
01231 
01232         curCertAsNameAndKey = GetCurrentCert(reverseState);
01233     }while(curCertAsNameAndKey != (IPKIFNameAndKey*)NULL);
01234 
01235     if(curCertAsNameAndKey == (IPKIFNameAndKey*)NULL)
01236         return false;
01237     else
01238     {
01239         //need to mark nodes as ignored where the name chaining is broken
01240         CPKIFNamePtr issuerName;
01241         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator pos;
01242         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator end = reverseState->m_table.rend();
01243         for(pos = reverseState->m_table.rbegin(); pos != end; ++pos)
01244         {
01245             if(issuerName == (CPKIFName*)NULL)
01246                 issuerName = (*pos)->front()->GetNameAndKey()->GetSubjectName();
01247             else
01248             {
01249                 IgnoreNotIssuedBy(*pos, issuerName);
01250                 issuerName = (*pos)->front()->GetNameAndKey()->GetSubjectName();
01251             }
01252         }
01253 
01254         return true;
01255     }
01256 
01257     return false;
01258 }
01259 
01269 bool CPKIFReversiblePathBuilderImpl::TriedBefore(CPKIFNameAndKeyWithScoreList& builtPathNK)
01270 {
01271     std::vector<CPKIFNameAndKeyWithScoreList>::iterator pos;
01272     std::vector<CPKIFNameAndKeyWithScoreList>::iterator end = m_previouslyTriedPaths.end();
01273     for(pos = m_previouslyTriedPaths.begin(); pos != end; ++pos)
01274     {
01275         if((*pos).size() != builtPathNK.size())
01276             return false;
01277 
01278         for(size_t ii = 0; ii < (*pos).size(); ++ii)
01279         {
01280             if(!((*pos)[ii] == builtPathNK[ii]))
01281                 return false;
01282         }
01283     }
01284     return !m_previouslyTriedPaths.empty();
01285 }
01286 
01296 bool CPKIFReversiblePathBuilderImpl::CheckAlternatives(CPKIFCertificatePath& path, CPKIFReversePathStatePtr& reverseState)
01297 {
01298     //if the table is incomplete (i.e. there is only the root row or target row) return false
01299     if(1 >= reverseState->m_table.size())
01300         return false;
01301 
01302     CPKIFBuilderStatisticsPtr bs;
01303     path.GetBuilderStats(bs);
01304 
01305     do
01306     {
01307         if(reverseState->m_curRoot == NULL)
01308         {
01309             //we haven't been here before
01310             CPKIFNameAndKeyWithScorePtr rootNK = reverseState->m_table.back()->front();
01311             reverseState->m_curRoot = dynamic_pointer_cast<IPKIFTrustAnchor, IPKIFNameAndKey>(rootNK->GetNameAndKey());
01312         }
01313         else
01314         {
01315             //if we didn't move the ignore pointer on the root row
01316             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator tablePos;
01317             vector<CPKIFNameAndKeyWithScoreListPtr>::iterator tableEnd = reverseState->m_table.end();
01318             for(tablePos = reverseState->m_table.begin(); tablePos != tableEnd; ++tablePos)
01319             {
01320 
01321 #ifdef _DEBUG
01322                 const char* frontNodeInCurRowName = (*tablePos)->front()->GetNameAndKey()->GetSubjectName()->ToString();
01323 #endif
01324                 if(!SetNextToIgnore(*tablePos))
01325                 {
01326                     //if we do not need to advance the row then break out of this loop
01327                     break;
01328                 }
01329                 else
01330                 {
01331                     //if we do need to advance the row the clear all ignored flags in the current row
01332                     ClearAllIgnore(*tablePos);
01333                 }
01334             }
01335             if(tablePos == tableEnd)
01336             {
01337                 bool liveMore = false;
01338 
01339                 //advance the ignored pointer in the trust root list (if there's more than one root)
01340                 if(reverseState->m_table.front()->size() > 1)
01341                 {
01342                     bool setNext = false;
01343                     CPKIFNameAndKeyWithScoreList::iterator rootPos;
01344                     CPKIFNameAndKeyWithScoreList::iterator rootEnd = reverseState->m_table.front()->end();
01345                     for(rootPos = reverseState->m_table.front()->begin(); rootPos != rootEnd; ++rootPos)
01346                     {
01347                         IPKIFTrustAnchorPtr ta = dynamic_pointer_cast<IPKIFTrustAnchor, IPKIFNameAndKey>((*rootPos)->GetNameAndKey());
01348                         if(setNext)
01349                         {
01350                             reverseState->m_curRoot = ta;
01351                             liveMore = true;
01352                             break;
01353                         }
01354                         else
01355                         {
01356                             if(*reverseState->m_curRoot == *ta)
01357                                 setNext = true;
01358                         }
01359                     }
01360                 }
01361                 
01362                 if(!liveMore)
01363                 {
01364                     return false;//no more alternatives in this table - return false
01365                 }
01366             }
01367         }
01368 
01369         //this code iterates over the table and populates builtPath with the first non-ignored
01370         //node that isn't already in the path (same DN/same public key) that was issued by the previous
01371         //node in the list.
01372         CPKIFNameAndKeyWithScoreList builtPathNK;
01373         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator pos;
01374         vector<CPKIFNameAndKeyWithScoreListPtr>::reverse_iterator end = reverseState->m_table.rend();
01375         CPKIFNameAndKeyWithScorePtr curEntry;
01376         bool hasCycle = false;
01377         PKIInfoSource pathMaxSource = LOCAL;
01378 
01379         IPKIFNameAndKeyPtr lastCert = dynamic_pointer_cast<IPKIFNameAndKey, IPKIFTrustAnchor>(reverseState->m_curRoot);
01380 
01381         CPKIFPathSettingsPtr settings; 
01382         path.GetPathSettings(settings);
01383 
01384         pos = reverseState->m_table.rbegin();
01385         for(++pos; pos != end; ++pos)
01386         { 
01387             curEntry = GetFirstNonIgnoredNodeNotAlreadyInPathIssuedBy(*pos, builtPathNK,lastCert,settings);
01388             if(curEntry != (CPKIFCertificateNodeEntry*)NULL     //check for NULL
01389                 && !curEntry->GetNameAndKey()->SameDNSameKey(*lastCert))    //make sure TA DN and key are not repeated
01390             {
01391                 builtPathNK.push_back(curEntry);
01392 
01393                 IPKIFNameAndKeyPtr emptyNK;
01394                 lastCert = emptyNK;
01395                 lastCert = curEntry->GetNameAndKey();
01396             }
01397             else
01398             {
01399                 hasCycle = true; //this path has a cycle - try another
01400                 break;
01401             }
01402         }
01403 
01404         ++bs->m_nTotalPathsDiscovered;
01405 
01406         //if the effort to build through current table state produced a cycle 
01407         //give another pass through the do...while by moving the ignored pointer
01408         if(hasCycle || TriedBefore(builtPathNK))
01409             continue;
01410 
01411         m_previouslyTriedPaths.push_back(builtPathNK);
01412 
01413         CPKIFCertificateNodeList builtPath;
01414         CPKIFNameAndKeyWithScoreList::iterator nkPos;
01415         CPKIFNameAndKeyWithScoreList::iterator nkEnd = builtPathNK.end();
01416 
01417         for(nkPos = builtPathNK.begin();nkPos != nkEnd; ++nkPos)
01418         {
01419             CPKIFCertificatePtr tmpCert = dynamic_pointer_cast<CPKIFCertificate, IPKIFNameAndKey>((*nkPos)->GetNameAndKey());
01420             CPKIFCertificateNodeEntryPtr newNode(new CPKIFCertificateNodeEntry(tmpCert));
01421             builtPath.push_back(newNode);
01422         }
01423 
01424 
01425         //perform basic validation checks
01426         CPKIFPathValidationResults tmpResults;
01427         if(settings->GetUseValidatorFilterWhenBuilding() && !PathOK(builtPath, reverseState->m_curRoot, settings, tmpResults))
01428         {
01429             ++bs->m_nPathsRejectedDueToValidationErrors;
01430             bs->m_vFailureCodes.push_back(tmpResults.DiagnosticCode());
01431 //          SearchForFailure(reverseState, builtPath);
01432 
01433             CPKIFCertificatePath tmpPath;
01434             CPKIFCertificatePtr tmpTarget;
01435             path.GetTarget(tmpTarget);
01436             tmpPath.SetTrustRoot(reverseState->m_curRoot);
01437             tmpPath.SetPath(builtPath);
01438             tmpPath.SetTarget(tmpTarget);
01439 
01440             CPKIFPathLogger::LogValidationResults(tmpResults, tmpPath, "Logging builder-rejected path"); //added 04/18/2003 CRW
01441             continue;
01442         }
01443 
01444         path.SetTrustRoot(reverseState->m_curRoot);
01445         path.SetPath(builtPath);
01446 
01447         CPKIFCertificateNodeList::iterator dbgpos;
01448         CPKIFCertificateNodeList::iterator dbgend = builtPath.end();
01449         if(LOCAL == pathMaxSource)
01450         {
01451             LOG_STRING_DEBUG("Printing path returned from BuildPath (LOCAL-certs only)...", m_parent->thisComponent, 0, NULL);
01452         }
01453         else
01454         {
01455             LOG_STRING_DEBUG("Printing path returned from BuildPath (LOCAL and REMOTE certs)...", m_parent->thisComponent, 0, NULL);
01456         }
01457         std::string logStr = "Root: ";
01458         logStr.append(((reverseState->m_curRoot))->GetSubjectName()->ToString());
01459         LOG_STRING_DEBUG(logStr.c_str(), m_parent->thisComponent, 0, NULL);
01460 
01461         for(dbgpos = builtPath.begin(); dbgpos != dbgend; ++dbgpos)
01462         {
01463             const char* curCertString = (*dbgpos)->GetCert()->Subject()->ToString();
01464             logStr = curCertString;
01465             logStr.append(" ");
01466             logStr.append((*dbgpos)->GetCert()->SerialNumber());
01467             LOG_STRING_DEBUG(logStr.c_str(), m_parent->thisComponent, 0, NULL);
01468         }
01469         ++bs->m_nReturnedPaths;
01470         return true;
01471     }while(1);
01472 
01473 }
01474 
01476 
01484 CPKIFReversiblePathBuilder::CPKIFReversiblePathBuilder(PathBuildingDirection pbd)
01485 :m_impl(new CPKIFReversiblePathBuilderImpl)
01486 {
01487     LOG_STRING_DEBUG("CPKIFReversiblePathBuilder::CPKIFReversiblePathBuilder", thisComponent, 0, this);
01488     m_impl->m_parent = this;
01489     m_impl->m_pbd = pbd;
01490 }
01491 
01499 CPKIFReversiblePathBuilder::~CPKIFReversiblePathBuilder(void)
01500 {
01501     if(m_impl)
01502     {
01503         delete m_impl;
01504         m_impl = 0;
01505     }
01506 }
01507 
01515 void CPKIFReversiblePathBuilder::Initialize()
01516 {
01517     LOG_STRING_DEBUG("CPKIFReversiblePathBuilder::Initialize()", thisComponent, 0, this);
01518 }
01519 
01530 bool CPKIFReversiblePathBuilder::BuildPath(
01534     CPKIFCertificatePath& path)
01535 {
01536     LOG_STRING_DEBUG("CPKIFReversiblePathBuilder::BuildPath(CPKIFCertificatePath& path)", thisComponent, 0, this);
01537 
01538     //----------------------------------------------------------------------------------------------------
01539     // these may need to be parameters and this function simply invoked from the CPKIFPathBuild and CPKIFPathReverseBuild classes
01540     PathBuildingDirection pbd = m_impl->m_pbd;
01541     //PathBuildingDirection pbd = PBD_REVERSE;
01542     //----------------------------------------------------------------------------------------------------
01543 
01544     //throws if there are any problems
01545     m_impl->CheckInputs(path);
01546 
01547     //at this point, we know we have a target and we know we have an IPKIFTrustCache interface.  see if 
01548     //the target is a trust anchor.  if it is, the building operation is complete.
01549     CPKIFCertificatePtr targetCert;
01550     path.GetTarget(targetCert);
01551     if(m_impl->TargetIsTrustAnchor(targetCert))
01552     {
01553         //if we find a trust root that matches the target then we're done, no need to build state and so forth
01554         CPKIFTrustRootPtr tr(new CPKIFTrustRoot());
01555         tr->SetCert(targetCert);
01556         path.SetTrustRoot(tr);
01557 
01558         //then set the path to a list containing only the target
01559         CPKIFCertificateNodeList builtPath;
01560         CPKIFCertificateNodeEntryPtr curEntry(new CPKIFCertificateNodeEntry);
01561         curEntry->SetCert(targetCert);
01562 
01563         CPKIFCertStatusPtr newStatus(new CPKIFCertStatus);
01564         newStatus->SetIsTrustAnchor(true);
01565         curEntry->SetStatus(newStatus);
01566 
01567         builtPath.push_back(curEntry);
01568         path.SetPath(builtPath);
01569 
01570         std::ostringstream os;
01571         os << "Path building is not required.  The target certificate is a trust root - subject DN = " << targetCert->GetSubjectName()->ToString();
01572         LOG_STRING_INFO(os.str().c_str(), thisComponent, 0, this);
01573 
01574         return true;
01575     }
01576 
01577     //see if we have a state object
01578     CPKIFCertificatePathStatePtr state;
01579     path.GetState(state);
01580 
01581     //if there was state, see if we can cast it to a type that this builder uses
01582     CPKIFReversePathStatePtr reverseState = dynamic_pointer_cast<CPKIFReversePathState, CPKIFCertificatePathState>(state);
01583     if(state == (CPKIFCertificatePathState*)NULL || reverseState == (CPKIFReversePathState*)NULL)
01584     {
01585         //if not, set it aside and create a new state object
01586         m_impl->CreateState(path, pbd);
01587     }
01588 
01589     path.GetState(state);
01590     reverseState = dynamic_pointer_cast<CPKIFReversePathState, CPKIFCertificatePathState>(state);
01591 
01592     //at this point, we have a table in the state object.  we now need to add a row in the quest towards
01593     //building to the other end point.
01594     do
01595     {
01596         //if the table is complete and there's a viable alternative, return true and let the validator take over
01597         if(reverseState->m_bTableIsComplete && m_impl->CheckAlternatives(path, reverseState))
01598             return true;
01599     }while(m_impl->BuildOrGrowTable(reverseState));
01600 
01601     //no more paths - we could no longer grow the table and the current alternatives have been exhausted
01602     return false;   
01603 }
01604 
01612 PathBuildingDirection CPKIFReversiblePathBuilder::GetDirection() const
01613 {
01614     return m_impl->m_pbd;
01615 }

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