SimpleCRLCache.cpp

Go to the documentation of this file.
00001 
00009 #include "SimpleCRLCache.h"
00010 #include "PKIFCacheErrors.h"
00011 #include "ToolkitUtils.h" 
00012 #include "GottaMatch.h"
00013 #include "CRL.h"
00014 #include "DPAndCRLPair.h"
00015 #include "Certificate.h"
00016 #include "GeneralName.h"
00017 #include "PKIFTime.h"
00018 #include "Buffer.h"
00019 #include "PKIFCacheException.h"
00020 #include "CRLPassedNextUpdate.h"
00021 #include "PKIFPathSettings.h"
00022 
00023 #include "boost/filesystem/operations.hpp"
00024 #include "boost/filesystem/path.hpp"
00025 #include "boost/thread/recursive_mutex.hpp"
00026 
00027 #include "boost/numeric/conversion/cast.hpp"
00028 #include "boost/numeric/conversion/bounds.hpp"
00029 #include "boost/limits.hpp"
00030 
00031 using boost::numeric_cast;
00032 using boost::bad_numeric_cast;
00033 
00034 #include <sstream>
00035 #ifdef _DEBUG
00036 #include <iostream>
00037 #endif //_DEBUG
00038 
00039 
00040 namespace fs = boost::filesystem;
00041 using namespace std;
00042 
00044 struct SimpleCRLCacheImpl
00045 {
00046     SimpleCRLCache * m_parent;
00054     SimpleCRLCacheImpl ():m_me() 
00055     {   
00056         m_parent = 0;
00057     };
00065     SimpleCRLCacheImpl (SimpleCRLCache  *p) :m_me()
00066     {
00067         m_parent = p;
00068     }
00070     CPKIFCRLList m_crlList;
00071     //CACMonitorDataPtr m_md;
00072     boost::recursive_mutex m_me;
00074     DPAndCRLPairList m_dpCRLList;
00075 
00076     bool m_bAutoCleanup;
00077     unsigned long m_interval;
00078     
00079     vector<string> m_pathList;
00080 
00081     unsigned long m_lastTickCount;
00083     bool NeedToCheckForOldCRLs();
00085     void CheckForAndRemoveOldCRLs();
00086 };
00088 
00096 CAC_API SimpleCRLCache* MakeSimpleCRLCache()
00097 {
00098     return new SimpleCRLCache();
00099 }
00107 CAC_API void FreeSimpleCRLCache(
00109     SimpleCRLCache* s)
00110 {
00111     if(s)
00112     {
00113         delete s;
00114     }
00115 }
00123 SimpleCRLCache::SimpleCRLCache(void)
00124     :m_impl (new SimpleCRLCacheImpl)
00125 {
00126     LOG_STRING_DEBUG("SimpleCRLCache::SimpleCRLCache(void)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00127 
00128     m_impl->m_parent = this;
00129     m_impl->m_bAutoCleanup=true;
00130     m_impl->m_lastTickCount = 0;
00131     m_impl->m_interval = 3600000;
00132 }
00140 SimpleCRLCache::~SimpleCRLCache(void)
00141 {
00142 //  LOG_STRING_DEBUG("SimpleCRLCache::~SimpleCRLCache(void)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00143 
00144     delete m_impl;
00145     m_impl = NULL;
00146 }
00147 
00155 int SimpleCRLCache::size()
00156 {
00157     int len = 0;
00158 
00159     try 
00160     {
00161         len = numeric_cast<int>(m_impl->m_crlList.size());
00162         return len;
00163     }
00164     catch(bad_numeric_cast &) 
00165     {
00166         throw CPKIFException(TOOLKIT_CACHE, COMMON_INVALID_INPUT, "Cache size is larger than maximum integer size.");
00167     }
00168 }
00169 
00170 //IPKIFColleague functions
00178 void SimpleCRLCache::Initialize(void)
00179 {
00180     LOG_STRING_DEBUG("SimpleCRLCache::Initialize(void)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00181 }
00191 void SimpleCRLCache::GetCRLs(
00193     const CPKIFCertificatePtr& cert,
00195     CPKIFCRLList& crlList,
00197     PKIInfoSource source)
00198 {
00199     LOG_STRING_DEBUG("SimpleCRLCache::GetCRLs(const CPKIFCertificatePtr& cert, CPKIFCRLList& crlList, PKIInfoSource source)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00200 
00201 #ifdef _DEBUG
00202     //cout << "SimpleCRLCache size: " << m_impl->m_crlList.size() << endl;
00203 #endif
00204 
00205     //CCACSynchronizedObject so(m_impl->m_md);
00206     boost::recursive_mutex::scoped_lock lock(m_impl->m_me);
00207 
00208     const size_t origSize = crlList.size();
00209 
00210     if(m_impl->NeedToCheckForOldCRLs())
00211         m_impl->CheckForAndRemoveOldCRLs();
00212 
00213     //ignore requests for remote certificates
00214     if(REMOTE == source)
00215     {
00216         LOG_STRING_DEBUG("Skipping SimpleCRLCache colleague - searching REMOTE sources only", thisComponent, 0, this);
00217         return;
00218     }
00219 
00220     if(cert == (CPKIFCertificate*)NULL)
00221     {
00222         std::string reason;
00223         FormatErrorMessage(reason, "NULL certificate passed to GetCRLs.", COMMON_INVALID_INPUT);
00224         LOG_STRING_DEBUG(reason.c_str(), thisComponent, COMMON_INVALID_INPUT, this);
00225         return;
00226     }
00227 
00228     CPKIFNamePtr issuer = cert->Issuer();
00229     if(issuer == (CPKIFName*)NULL)
00230     {
00231         std::string reason;
00232         FormatErrorMessage(reason, "Certificate with NULL issuer passed to GetCRLs.", COMMON_INVALID_INPUT);
00233         LOG_STRING_DEBUG(reason.c_str(), thisComponent, COMMON_INVALID_INPUT, this);
00234         return;
00235     }
00236 
00237     CPKIFCRLList::iterator pos;
00238     CPKIFCRLList::iterator end = m_impl->m_crlList.end();
00239     for(pos = m_impl->m_crlList.begin(); pos != end; ++pos)
00240     {
00241         if(*issuer == *(*pos)->Issuer())
00242         {
00243             GottaMatch<CPKIFCRLPtr> gm;
00244             gm.SetRHS(*pos);
00245             if(crlList.end() == find_if(crlList.begin(), crlList.end(), gm))
00246                 crlList.push_back(*pos); 
00247         }
00248     }
00249 
00250     //DP based retrieval
00251     CPKIFGeneralNameList namesFromCert;
00252     CollectNamesFromCRLDP(cert, namesFromCert);
00253 
00254     CPKIFGeneralNameList::iterator gnPos;
00255     CPKIFGeneralNameList::iterator gnEnd = namesFromCert.end();
00256     for(gnPos = namesFromCert.begin(); gnPos != gnEnd; ++gnPos)
00257     {
00258         DPAndCRLPairList::iterator dpListPos;
00259         DPAndCRLPairList::iterator dpListEnd = m_impl->m_dpCRLList.end();
00260         for(dpListPos = m_impl->m_dpCRLList.begin(); dpListEnd != dpListPos; ++dpListPos)
00261         {
00262             //added proper de-reference (had been comparing smart pointers - oops)
00263             //2/19/2004 CRW
00264             if(*(*dpListPos)->m_dp == *(*gnPos))
00265             {
00266                 //added GottaMatch stuff 7/21/2005 CRW
00267                 GottaMatch<CPKIFCRLPtr> gm;
00268                 gm.SetRHS((*dpListPos)->m_crl);
00269                 if(crlList.end() == find_if(crlList.begin(), crlList.end(), gm))
00270                     crlList.push_back((*dpListPos)->m_crl);
00271             }
00272         }
00273 
00274         if(CPKIFGeneralName::DIRECTORYNAME == (*gnPos)->GetType())
00275         {
00276             CPKIFNamePtr dpDN = (*gnPos)->directoryName();
00277             if(dpDN != (CPKIFName*)NULL)
00278             {
00279                 CPKIFCRLList::iterator pos;
00280                 CPKIFCRLList::iterator end = m_impl->m_crlList.end();
00281                 for(pos = m_impl->m_crlList.begin(); pos != end; ++pos)
00282                 {
00283                     if(*dpDN == *(*pos)->Issuer())
00284                     {
00285                         //added GottaMatch stuff 7/21/2005 CRW
00286                         GottaMatch<CPKIFCRLPtr> gm;
00287                         gm.SetRHS(*pos);
00288                         if(crlList.end() == find_if(crlList.begin(), crlList.end(), gm))
00289                             crlList.push_back(*pos);
00290                     }
00291                 }
00292             }
00293         }
00294     }
00295 
00296     if(origSize != crlList.size())
00297     {
00298         std::string logStr = "Found one or more CRLs issued by ";
00299         logStr.append(cert->Issuer()->ToString());
00300         LOG_STRING_DEBUG(logStr.c_str(), thisComponent, 0, this);
00301     }
00302     else
00303     {
00304         std::string logStr = "Failed to find a CRL issued by ";
00305         logStr.append(cert->Issuer()->ToString());
00306         LOG_STRING_DEBUG(logStr.c_str(), thisComponent, 0, this);
00307     }
00308 }
00316 void SimpleCRLCache::Clear()
00317 {
00318     LOG_STRING_DEBUG("SimpleCRLCache::Clear()", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00319 
00320     //CCACSynchronizedObject so(m_impl->m_md);
00321     boost::recursive_mutex::scoped_lock lock(m_impl->m_me);
00322     LOG_STRING_DEBUG("Emptying SimpleCRLCache instance", thisComponent, 0, this);
00323     m_impl->m_crlList.clear();
00324 }
00333 void SimpleCRLCache::SetAutoCleanup(
00335     bool on, 
00337     unsigned long interval) 
00338 {
00339     LOG_STRING_DEBUG("SimpleCRLCache::SetAutoCleanup(bool on, int interval)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00340 
00341     //CCACSynchronizedObject so(m_impl->m_md);
00342     boost::recursive_mutex::scoped_lock lock(m_impl->m_me);
00343     m_impl->m_bAutoCleanup = on;
00344 
00345     m_impl->m_interval = interval;
00346 //  if(m_interval < 0)
00347 //      m_interval *= -1;
00348 }
00360 void SimpleCRLCache::AddCRL(
00362     const CPKIFCRLPtr& crl, 
00364     const CPKIFGeneralNamePtr& dp)
00365 {
00366     LOG_STRING_DEBUG("SimpleCRLCache::AddCRL(const CPKIFCRLPtr& crl, const CPKIFGeneralNamePtr& dp)", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00367 
00368     //CCACSynchronizedObject so(m_impl->m_md);
00369     boost::recursive_mutex::scoped_lock lock(m_impl->m_me);
00370     //This function adds a CRL to two internal vectors.  One vector will be used to retrieve
00371     //CRLs using issuer name from a cert and the other will use a distribution point from a cert.
00372     //Thus, if a CRL was retrieved from www.getyourcrlshere.com with an issuer name different from
00373     //the cert issuer (not that we support indirect CRLs in this version of PKIF) then the cache will 
00374     //still function.
00375 
00376     if(m_impl->NeedToCheckForOldCRLs())
00377         m_impl->CheckForAndRemoveOldCRLs();
00378 
00379     GottaMatch<CPKIFCRLPtr> gm;
00380     gm.SetRHS(crl);
00381 
00382     //avoid growing the cache with duplicates
00383     if(m_impl->m_crlList.end() == find_if(m_impl->m_crlList.begin(), m_impl->m_crlList.end(), gm))
00384     {
00385         m_impl->m_crlList.push_back(crl);
00386 
00387         std::ostringstream os;
00388         os << "Successfully added CRL to SimpleCRLCache store.  Size =  " << m_impl->m_crlList.size() << " after addition.";
00389         LOG_STRING_DEBUG(os.str().c_str(), thisComponent, 0, this)
00390     }
00391 
00392     //DP based CRL storage
00393     if(dp != (CPKIFGeneralName*)NULL)
00394     {
00395         DPAndCRLPairPtr newDPCRLPair(new DPAndCRLPair);
00396         newDPCRLPair->m_dp = dp;
00397         newDPCRLPair->m_crl = crl;
00398 
00399         GottaMatch<DPAndCRLPairPtr> gm2;
00400         gm2.SetRHS(newDPCRLPair);
00401         if(m_impl->m_dpCRLList.end() == find_if(m_impl->m_dpCRLList.begin(), m_impl->m_dpCRLList.end(), gm2))
00402         {
00403             m_impl->m_dpCRLList.push_back(newDPCRLPair);
00404 
00405             std::ostringstream os;
00406             os << "Successfully added DP CRL to SimpleCRLCache store.  Size =  " << m_impl->m_dpCRLList.size() << " after addition.";
00407             LOG_STRING_DEBUG(os.str().c_str(), thisComponent, 0, this)
00408         }
00409     }
00410 }
00420 void SimpleCRLCache::WriteCRLsToDirectory(
00422     const char * path)
00423 {
00424     try
00425     {
00426         std::string CRLdirPath  = path;
00427         CPKIFCRLList::iterator pos;
00428         CPKIFCRLList::iterator end = m_impl->m_crlList.end();
00429         for(pos = m_impl->m_crlList.begin(); pos != end; ++pos)
00430         {
00431             string tmpCRLName = (*pos)->Issuer()->ToString();           
00432             string tmpCRLThisUpdate = (*pos)->ThisUpdate()->GetTime();
00433             string tmpPath = CRLdirPath;
00434             if(tmpPath[tmpPath.size() -1] != '\\')
00435                 tmpPath.append("\\");
00436             tmpPath.append(tmpCRLName);
00437             tmpPath.append("_");
00438             tmpPath.append(tmpCRLThisUpdate);
00439             tmpPath.append(".crl");
00440 
00441             FILE* f = fopen(tmpPath.c_str(), "wb");
00442             fwrite((*pos)->Encoded()->GetBuffer(), 1, (*pos)->Encoded()->GetLength(), f);
00443             fclose(f);
00444         }
00445 
00446         DPAndCRLPairList::iterator pos2;
00447         DPAndCRLPairList::iterator end2 = m_impl->m_dpCRLList.end();
00448         for(pos2 = m_impl->m_dpCRLList.begin(); pos2 != end2; ++pos2)
00449         {
00450             string tmpCRLName = (*pos2)->m_crl->Issuer()->ToString();       
00451             string tmpCRLThisUpdate = (*pos)->ThisUpdate()->GetTime();
00452             string tmpPath = CRLdirPath;
00453             if(tmpPath[tmpPath.size() -1] != '\\')
00454                 tmpPath.append("\\");
00455             tmpPath.append(tmpCRLName);
00456             tmpPath.append("_");
00457             tmpPath.append(tmpCRLThisUpdate);
00458             tmpPath.append(".crl");
00459             
00460             FILE* f = fopen(tmpPath.c_str(), "wb");
00461             fwrite((*pos)->Encoded()->GetBuffer(), 1, (*pos)->Encoded()->GetLength(), f);
00462             fclose(f);
00463         }
00464     }catch( const std::exception&)
00465     {
00466             RAISE_CACHE_EXCEPTION("Error Writing files to a directory", thisComponent, COMMON_UNKNOWN_ERROR, this)
00467      }
00468 }
00469 
00484 void SimpleCRLCache::ReadCRLsFromDirectory(
00486     const char * path)
00487 {
00488     fs::path full_path( fs::initial_path() );
00489 
00490     if(NULL != path)
00491         full_path = fs::system_complete( fs::path( path, fs::native ) );
00492     else
00493         RAISE_CACHE_EXCEPTION("NULL Pointer passed as a parameter", thisComponent, COMMON_INVALID_INPUT, this)
00494 
00495     if ( !fs::exists( full_path ) )
00496     {
00497         RAISE_CACHE_EXCEPTION("Invalid Path", thisComponent, COMMON_INVALID_INPUT, this)
00498     }   
00499 
00500    fs::directory_iterator end_iter;
00501    for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr )
00502    {
00503        try
00504        {
00505            if ( !fs::is_directory( *dir_itr ) )
00506            {
00507                 FILE* f = fopen(dir_itr->string().c_str(), "rb");
00508 
00509                 unsigned char *crlraw = NULL;
00510 
00511                 //reviewed 4/24 - added bounds check below
00512                 boost::intmax_t crlrawlen = fs::file_size( *dir_itr );
00513 
00514                 if(crlrawlen > boost::numeric::bounds<int>::highest())
00515                 {
00516                     throw CPKIFCacheException(TOOLKIT_SR_SIMPLECRLCACHE, COMMON_INVALID_INPUT, "CRL too big.");
00517                 }
00518 
00519                 int tmpST = 0;
00520                 try 
00521                 {
00522                     tmpST = numeric_cast<int>(crlrawlen);
00523                 }
00524                 catch(bad_numeric_cast &) 
00525                 {
00526                     throw CPKIFException(TOOLKIT_UTILS, COMMON_INVALID_INPUT, "CRL size too big.");
00527                 }
00528 
00529                 crlraw = new unsigned char[tmpST];
00530                 size_t bytesread = fread(crlraw, 1, tmpST, f);
00531             
00532                 CPKIFCRLPtr crl(new CPKIFCRL);
00533                 crl->Decode(crlraw, tmpST);
00534             
00535                 CPKIFGeneralNamePtr dummy;
00536                 AddCRL(crl, dummy);
00537                 
00538                 fclose(f);
00539                 delete[] crlraw;
00540            }
00541        }
00542        catch( const std::exception & )
00543        {
00544             RAISE_CACHE_EXCEPTION("Unable to open file", thisComponent, COMMON_UNKNOWN_ERROR, this)
00545        }
00546 
00547    }
00548     
00549 }
00558 bool SimpleCRLCacheImpl::NeedToCheckForOldCRLs()
00559 {
00560     LOG_STRING_DEBUG("SimpleCRLCache::NeedToCheckForOldCRLs()", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00561 
00562     unsigned long tmpTickCount = GetTickCount();
00563     if((tmpTickCount - m_lastTickCount) > m_interval)
00564     {
00565         m_lastTickCount = tmpTickCount;
00566         return true;
00567     }
00568     else
00569         return false;
00570 }
00579 void SimpleCRLCacheImpl::CheckForAndRemoveOldCRLs()
00580 {
00581     LOG_STRING_DEBUG("SimpleCRLCache::CheckForAndRemoveOldCRLs()", TOOLKIT_SR_SIMPLECRLCACHE, 0, this);
00582 
00583     if(!m_bAutoCleanup)
00584         return;
00585 
00586     LOG_STRING_DEBUG("Purging old CRLs from SimpleCRLCache store", m_parent->thisComponent, 0, this);
00587 
00588     CRLPassedNextUpdate funcObj;
00589     // needed for g++ as opposed to
00590     // funcObj.SetCurTime(CPKIFTime::CurrentTime()
00591     CPKIFTimePtr now = CPKIFTime::CurrentTime();
00592     funcObj.SetCurTime(now);
00593     CPKIFCRLList::iterator crlEnd = remove_if(m_crlList.begin(), m_crlList.end(), funcObj);
00594     m_crlList.erase(crlEnd, m_crlList.end());
00595 
00596     DPAndCRLPairList::iterator dpEnd = remove_if(m_dpCRLList.begin(), m_dpCRLList.end(), funcObj);
00597     m_dpCRLList.erase(dpEnd, m_dpCRLList.end());
00598 }
00607 void SimpleCRLCache::GetCRLs(
00609     std::vector<CPKIFCRLPtr>& v)
00610 {
00611     CPKIFCRLList::iterator pos;
00612     CPKIFCRLList::iterator end = m_impl->m_crlList.end();
00613     for(pos = m_impl->m_crlList.begin(); pos != end; ++pos)
00614     {
00615         v.push_back(*pos);
00616     }
00617 }
00618 
00626 void CRLCoversTimeOfInterest::SetTimeOfInterest(
00628     CPKIFTimePtr& time) 
00629 {
00630     m_time = time;
00631 }
00632 bool CRLCoversTimeOfInterest::operator ()(const CPKIFCRLPtr& crl)
00633 {
00634     CPKIFTimePtr nextUpdate = crl->NextUpdate();
00635     CPKIFTimePtr thisUpdate = crl->ThisUpdate();
00636 
00637 #ifdef _DEBUG
00638     const char* thisUpdateStr = thisUpdate->GetTime();
00639     const char* toiStr = m_time->GetTime();
00640     if(nextUpdate)
00641     {
00642         const char* nextUpdateStr = nextUpdate->GetTime();
00643     }
00644 #endif
00645 
00646     if(nextUpdate == (CPKIFTime*)NULL)
00647         return false;
00648     else if(*nextUpdate < *m_time || *thisUpdate > *m_time)
00649         return true;
00650     else
00651         return false;
00652 }
00653 
00654 void SimpleCRLCache::GetCRLs(const CPKIFCertificatePtr& cert, CPKIFCRLList& crlList, PKIInfoSource source, CPKIFPathSettingsPtr& ps)
00655 {
00656     CPKIFCRLList tempCrlList;
00657     GetCRLs(cert, tempCrlList, source);
00658 
00659     CPKIFTimePtr valTime;
00660     if(ps)
00661         valTime = ps->GetValidationTime();
00662 
00663     if(valTime && ps->GetRequireValidationTimeNesting())
00664     {
00665         CRLCoversTimeOfInterest cctoi;
00666         cctoi.SetTimeOfInterest(valTime);
00667         CPKIFCRLList::iterator newEnd = remove_if(tempCrlList.begin(), tempCrlList.end(), cctoi);
00668         tempCrlList.erase(newEnd, tempCrlList.end());
00669     }
00670 
00671     copy(tempCrlList.begin(), tempCrlList.end(), back_inserter(crlList));
00672 }

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