PKIFNSSRepository.cpp

Go to the documentation of this file.
00001 
00010 #include "PKIFNSSRepository.h"
00011 #include "PKIFNSSHelper.h"
00012 
00013 #include "PKIFNSSDatabase.h"
00014 #include "PKIFNSSErrors.h"
00015 #include "ToolkitUtils.h"
00016 #include "components.h"
00017 #include "PKIFCacheErrors.h"
00018 #include "Buffer.h"
00019 #include "Certificate.h"
00020 #include "CRL.h"
00021 #include "Name.h"
00022 #include "PKIFTrustRoot.h"
00023 #include "PKIFCacheException.h"
00024 #include "GottaMatch.h"
00025 
00026 #include "IPKIFSearchCriteria.h"
00027 #include "KeyIDBasedSearch.h"
00028 #include "NameBasedSearch.h"
00029 #include "IssuerNameAndSerialNumberBasedSearch.h"
00030 
00031 #include "PKIFNSSConfig.h"
00032 
00033 #include "boost/numeric/conversion/cast.hpp"
00034 #include "boost/numeric/conversion/bounds.hpp"
00035 #include "boost/limits.hpp"
00036 
00037 using boost::numeric_cast;
00038 using boost::bad_numeric_cast;
00039 
00040 #include <sstream>
00041 using namespace std;
00042 
00044 struct PKIFNSSRepositoryImpl
00045 {
00046     CERTCertDBHandle * m_certDbHandle;
00047     CPKIFNSSDatabase * m_db;
00048 };
00050 
00051 // throws if this is a different database than the one that's open
00063 CPKIFNSSRepository::CPKIFNSSRepository(
00065     const std::string & dbdir)
00066 :m_impl(new PKIFNSSRepositoryImpl)
00067 {
00068     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00069     m_impl->m_certDbHandle = 0;
00070     m_impl->m_db = 0;
00071     // since it doesn't make since in SR to use NSS without a DB,
00072     // if no dbdir is specified, we'll use what's open already
00073     if(dbdir == "") {
00074         m_impl->m_db = CPKIFNSSDatabase::GetInstance();
00075     } else {
00076         // this will throw if the database has already been opened
00077         // with a diferent directory, as we can only have one open
00078         // at a time
00079         m_impl->m_db = CPKIFNSSDatabase::GetInstance(dbdir);
00080     }
00081 }
00089 CPKIFNSSRepository::~CPKIFNSSRepository(void)
00090 {
00091     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00092     PKIFDelete(m_impl);
00093     m_impl = 0;
00094 }
00106 void CPKIFNSSRepository::GetCertificates(
00108     const CPKIFNamePtr& subDN, 
00110     CPKIFCertificateList& certList, 
00112     PKIInfoSource source)
00113 {
00114     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00115     if(0 == m_impl->m_certDbHandle)
00116     {
00117         RAISE_CACHE_EXCEPTION("CPKIFNSSRepository instance not initialized.", thisComponent, COMMON_NOT_INITIALIZED, this)
00118     }
00119     if(source == REMOTE) return;
00120     CERTCertList *certs = 0;
00121     SECItem nameItem;
00122     nameItem.type = siBuffer;
00123     
00124     CPKIFBufferPtr encName = subDN->Encoded();
00125     nameItem.data = (unsigned char *)encName->GetBuffer();
00126     nameItem.len = encName->GetLength();
00127     
00128     // get all certs in the NSS database with the specified subject name
00129     certs = CERT_CreateSubjectCertList(0,m_impl->m_certDbHandle,&nameItem,
00130         PR_Now(),PR_FALSE);
00131 
00132     // fast search failed. try the slow search
00133 #if 0
00134     if(!certs) {
00135         CERTCertificate * found = CERT_FindCertByNameString(m_impl->m_certDbHandle,subDN->string());
00136         if(found) {
00137             certs = CERT_CertListFromCert(found);
00138         }
00139     }
00140 #endif
00141 
00142     if(!certs) {
00143         return;
00144     }
00145 
00146     CERTCertListNode *node = CERT_LIST_HEAD(certs);
00147     while(!CERT_LIST_END(node,certs)) {
00148         CERTCertificate * foundCert = node->cert;
00149         CPKIFCertificatePtr tmpCert(new CPKIFCertificate());
00150         try {
00151             tmpCert->Decode(foundCert->derCert.data, foundCert->derCert.len);
00152         }catch(CPKIFException &){
00153             //ignore parse failure
00154             std::ostringstream os;
00155             os << "Failed to parse certificate from NSS store searching for certificates issued to: " << subDN->ToString();
00156             LOG_STRING_ERROR(os.str().c_str(), thisComponent, CACHE_PARSE_ERROR, this);
00157         }
00158         GottaMatch<CPKIFCertificatePtr> gm;
00159         gm.SetRHS(tmpCert);
00160         if(certList.end() == find_if(certList.begin(), certList.end(), gm)) {
00161             certList.push_back(tmpCert);
00162         }
00163         node = CERT_LIST_NEXT(node);
00164     }
00165     CERT_DestroyCertList(certs);
00166 }
00178 void CPKIFNSSRepository::GetCRLs(
00180     const CPKIFCertificatePtr& cert, 
00182     CPKIFCRLList& crlList, 
00184     PKIInfoSource source)
00185 {
00186     // as far as I can tell, NSS is only going to give out one CRL
00187     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00188     if(0 == m_impl->m_certDbHandle)
00189     {
00190         RAISE_CACHE_EXCEPTION("CPKIFNSSRepository instance not initialized.", thisComponent, COMMON_NOT_INITIALIZED, this)
00191     }
00192     if(source == REMOTE) return;
00193     // even though NSS exports the appealingly named SEC_FindCrlByDERCert, I don't believe
00194     // anyone uses that and it looks like despite the name it might not work the way it
00195     // sounds like it should. NSS uses the issuer name as the db key anyway...
00196     CERTSignedCrl *crl = 0;
00197     SECItem derIssName;
00198     CPKIFBufferPtr tmpIssName = cert->Issuer()->Encoded();
00199     derIssName.type = siBuffer;
00200     derIssName.data = (unsigned char *)tmpIssName->GetBuffer();
00201     derIssName.len = tmpIssName->GetLength();
00202     crl  = SEC_FindCrlByName(m_impl->m_certDbHandle,&derIssName,SEC_CRL_TYPE);
00203     if(!crl) {
00204         return;
00205     }
00206     CPKIFCRLPtr tmpCRL(new CPKIFCRL());
00207     try {
00208         tmpCRL->Decode(crl->derCrl->data,crl->derCrl->len);
00209     }catch(CPKIFException &){
00210             std::ostringstream os;
00211             os << "Failed to parse CRL from NSS store searching for CRLs issued for: " << cert->Issuer()->ToString();
00212             LOG_STRING_ERROR(os.str().c_str(), thisComponent, CACHE_PARSE_ERROR, this);
00213     }
00214     SEC_DestroyCrl(crl);
00215     GottaMatch<CPKIFCRLPtr> gm;
00216     gm.SetRHS(tmpCRL);
00217     if(crlList.end() == find_if(crlList.begin(), crlList.end(), gm)) {
00218         crlList.push_back(tmpCRL);
00219     }
00220 }
00228 void CPKIFNSSRepository::Initialize(void)
00229 {
00230     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00231     if(!CPKIFNSSHelper::NSSAvaliable()) {
00232         RAISE_CACHE_EXCEPTION("NSS could not be loaded.",thisComponent,PKIFNSS_INIT_FAILED,this);
00233     }
00234     m_impl->m_certDbHandle = CERT_GetDefaultCertDB();
00235 }
00236 
00237 
00238 void CPKIFNSSRepository::FindCertificates(
00240     IPKIFSearchCriteria* searchCriteria,
00242     CPKIFCertificateList& certList,
00244     PKIInfoSource source)
00245 {
00246     LOG_STRING_DEBUG(__FUNCTION__,TOOLKIT_SR_NSSREPOSITORY,0,this);
00247     if(0 == m_impl->m_certDbHandle)
00248     {
00249         RAISE_CACHE_EXCEPTION("CPKIFNSSRepository instance not initialized.", thisComponent, COMMON_NOT_INITIALIZED, this)
00250     }
00251     if(source == REMOTE) return;
00252     CERTCertificate * found = 0;
00253     SECItem nameItem;
00254 
00255 
00256     switch(searchCriteria->GetSearchType())
00257     {
00258     case ALLCERTS:
00259         break;
00260     case ISSUERNAME:
00261         break;
00262     case SUBJECTNAME:
00263         {
00264             nameItem.type = siBuffer;
00265 
00266             CPKIFNameBasedSearch* nbs = dynamic_cast<CPKIFNameBasedSearch*>(searchCriteria);
00267             CPKIFBufferPtr encName = nbs->GetName()->Encoded();
00268             nameItem.data = (unsigned char *)encName->GetBuffer();
00269             nameItem.len = encName->GetLength();
00270             if(0 != nameItem.data)
00271             {   
00272                 found = CERT_FindCertByName(m_impl->m_certDbHandle,&nameItem);
00273 
00274             }
00275             else
00276                 return;
00277         }
00278         break;
00279     case ISSUERSERIAL:
00280         {
00281             CERTIssuerAndSN issuerSN;
00282             CPKIFIssuerNameAndSerialNumberBasedSearch* inasnbs = dynamic_cast<CPKIFIssuerNameAndSerialNumberBasedSearch*>(searchCriteria);
00283             CPKIFNamePtr issuerName = inasnbs->GetIssuerName();
00284             CPKIFBufferPtr encName = issuerName->Encoded();
00285             issuerSN.derIssuer.data = (unsigned char *)encName->GetBuffer();
00286             issuerSN.derIssuer.len = encName->GetLength();
00287             issuerSN.derIssuer.type = siBuffer;
00288 
00289             const char* sn = inasnbs->GetSerialNumber();
00290 
00291             size_t len = strlen(sn) - 2;
00292             unsigned int iLen = 0;
00293             if(len > boost::numeric::bounds<unsigned int>::highest())
00294             {
00295                 throw CPKIFCacheException(TOOLKIT_SR_CAPIUSERREPOSITORY, COMMON_INVALID_INPUT, "Serial number too big.");
00296             }
00297             else
00298                 iLen = numeric_cast<unsigned int>(len);
00299 
00300             unsigned char* binSN = new unsigned char[iLen];
00301             atob((char*)binSN, (char*)sn+2, &iLen);
00302             //ReverseBytes(binSN, iLen);
00303             issuerSN.serialNumber.data = binSN;
00304             issuerSN.serialNumber.len = iLen;
00305             issuerSN.serialNumber.type = siBuffer;
00306 
00307 
00308             if(0 != issuerSN.serialNumber.data && issuerSN.derIssuer.data)
00309             {   
00310                 found = CERT_FindCertByIssuerAndSN(m_impl->m_certDbHandle,&issuerSN);
00311             }
00312             else
00313                 return;
00314             break;
00315         }
00316     case KEYID:
00317         {
00318             CPKIFKeyIDBasedSearch* kidbs = dynamic_cast<CPKIFKeyIDBasedSearch*>(searchCriteria);
00319             if(!kidbs)
00320                 return;
00321 
00322             CPKIFBufferPtr kid = kidbs->GetKeyID();
00323             nameItem.data = (unsigned char *)kid->GetBuffer();
00324             nameItem.len = kid->GetLength();
00325             if(0 != nameItem.data)
00326             {   
00327                 found = CERT_FindCertBySubjectKeyID(m_impl->m_certDbHandle,&nameItem);
00328 
00329             }
00330             else
00331                 return;
00332             break;
00333         }
00334     default:
00335         return;
00336     };
00337 
00338     if(!found) {
00339         return;
00340     }
00341 
00342 
00343     CPKIFCertificatePtr tmpCert(new CPKIFCertificate());
00344     try {
00345         tmpCert->Decode(found->derCert.data, found->derCert.len);
00346     }catch(CPKIFException &){
00347         //ignore parse failure
00348         std::ostringstream os;
00349         os << "Failed to parse certificate from NSS store.";
00350         LOG_STRING_ERROR(os.str().c_str(), thisComponent, CACHE_PARSE_ERROR, this);
00351     }
00352     GottaMatch<CPKIFCertificatePtr> gm;
00353     gm.SetRHS(tmpCert);
00354     if(certList.end() == find_if(certList.begin(), certList.end(), gm)) {
00355         certList.push_back(tmpCert);
00356     }
00357 }

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