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
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
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
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
00203 #endif
00204
00205
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
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
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
00263
00264 if(*(*dpListPos)->m_dp == *(*gnPos))
00265 {
00266
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
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
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
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
00347
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
00369 boost::recursive_mutex::scoped_lock lock(m_impl->m_me);
00370
00371
00372
00373
00374
00375
00376 if(m_impl->NeedToCheckForOldCRLs())
00377 m_impl->CheckForAndRemoveOldCRLs();
00378
00379 GottaMatch<CPKIFCRLPtr> gm;
00380 gm.SetRHS(crl);
00381
00382
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
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
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
00590
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 }