00001
00009 #include "GeneralSubtree.h"
00010 #include "GeneralName.h"
00011 #include "Name.h"
00012 #include "ASN1Helper.h"
00013
00014 #include "PKIX1Implicit88.h"
00015 #include "PKIX1Explicit88.h"
00016
00017 #include "components.h"
00018 #include "PKIFException.h"
00019
00020 #include "boost/regex.hpp"
00021 #include "boost/algorithm/string.hpp"
00022 #include "boost/numeric/conversion/cast.hpp"
00023
00024 using boost::numeric_cast;
00025 using boost::bad_numeric_cast;
00026
00027 #include <string>
00028 #include <sstream>
00029 using namespace std;
00030
00031
00032
00033
00034 static bool emailre_init = false;
00035 static const char * emailpat = "([\\w\\d!\"#$%&'*+-/=?@^_`{|}~]+)@([\\w\\d!\"#$%&'*+-/=?@^_`{|}~]+\\.)([\\w\\d!\"#$%&'*+-/=?@^_`{|}~]+)(\\.[\\w\\d!\"#$%&'*+-/=?@^_`{|}~]+)*";
00036 static boost::regex emailre;
00037
00038 static bool escapere_init = false;
00039 static const char * escapepat = "\\.";
00040 static const char * escapeformat = "\\\\.";
00041 static boost::regex escapere;
00042
00043 static bool urire_init = false;
00044
00045 static const char * uripat = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?";
00046 static boost::regex urire;
00047 static const char * portpat = "(.*):(\\d+)?$";
00048 static boost::regex portre;
00049
00050 static bool erdnre_init = false;
00051 static const char * erdnpat = "^e=(.*)$";
00052 static boost::regex erdnre;
00053
00061 static std::string getHost(const std::string & uri)
00062 {
00063 if(!urire_init) {
00064 urire.assign(uripat,boost::regex_constants::perl);
00065 portre.assign(portpat,boost::regex_constants::perl);
00066 urire_init = true;
00067 }
00068 boost::smatch what;
00069 std::string rv("");
00070 bool found = boost::regex_match(uri,what,urire);
00071 if(found){
00072 rv.assign(what[4].first,what[4].second);
00073 boost::smatch pm;
00074
00075
00076 found = boost::regex_match(rv,pm,portre);
00077 if(found) {
00078 rv.assign(pm[1].first,pm[1].second);
00079 }
00080 }
00081 return rv;
00082 }
00083
00091 static std::string escapeDots(const std::string & inpat)
00092 {
00093 if(!escapere_init) {
00094 escapere.assign(escapepat,boost::regex_constants::perl);
00095 escapere_init = true;
00096 }
00097 ostringstream os;
00098 ostream_iterator<char> oi(os);
00099 boost::regex_replace(oi,inpat.begin(),inpat.end(),escapere,escapeformat,
00100 boost::match_default | boost::format_all);
00101 return os.str();
00102 }
00103
00113 static bool isEmail(
00115 const std::string & addr)
00116 {
00117 if(!emailre_init) {
00118 emailre.assign(emailpat,boost::regex_constants::perl);
00119 emailre_init = true;
00120 }
00121 boost::smatch what;
00122 bool found = boost::regex_search(addr,what,emailre);
00123 if(!found)
00124 {
00125 if(!urire_init) {
00126 urire.assign(uripat,boost::regex_constants::perl);
00127 portre.assign(portpat,boost::regex_constants::perl);
00128 urire_init = true;
00129 }
00130 boost::smatch what;
00131 found = boost::regex_match(addr,what,urire);
00132 }
00133 return found;
00134 }
00135
00137
00138 struct CPKIFGeneralSubtreeImpl
00139 {
00140 CPKIFGeneralNamePtr m_base;
00141 int m_nMin;
00142 int m_nMax;
00143 bool m_empty;
00144
00145 CPKIFGeneralSubtree::MatchState DNSNameIsInSubtree(const char * name);
00146 CPKIFGeneralSubtree::MatchState IPAddressIsInSubtree(const CPKIFBufferPtr & name);
00147 CPKIFGeneralSubtree::MatchState RFC822NameIsInSubtree(const char * name);
00148 CPKIFGeneralSubtree::MatchState URINameIsInSubtree(const char * name);
00149
00150 };
00151
00161 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtreeImpl::DNSNameIsInSubtree(const char * name)
00162 {
00163 if(CPKIFGeneralName::DNSNAME != m_base->GetType()) return CPKIFGeneralSubtree::NOT_APPLICABLE;
00164 if(m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00165
00166
00167
00168
00169
00170
00171 string base(m_base->dnsName());
00172 string cand(name);
00173
00174
00175 boost::regex_constants::syntax_option_type reflags =
00176 boost::regex_constants::perl | boost::regex_constants::icase;
00177
00178 ostringstream patstream;
00179 patstream << base << "$";
00180 string pattern = escapeDots(patstream.str());
00181 boost::regex re;
00182 boost::smatch what;
00183
00184 re.assign(pattern,reflags);
00185 bool found = boost::regex_search(cand,what,re);
00186
00187
00188
00189 if(!found) return CPKIFGeneralSubtree::NO_MATCH;
00190
00191
00192 if(cand.length() == base.length()) return CPKIFGeneralSubtree::MATCH;
00193
00194
00195
00196 int pos;
00197 try {
00198 pos = numeric_cast<int>(what.position());
00199 }catch(bad_numeric_cast &) {
00200 throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered abusively long dns name");
00201 }
00202 if(pos && cand[pos-1] == '.') return CPKIFGeneralSubtree::MATCH;
00203
00204 return CPKIFGeneralSubtree::NO_MATCH;
00205 }
00206
00218 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtreeImpl::IPAddressIsInSubtree(const CPKIFBufferPtr & name)
00219 {
00220 if(CPKIFGeneralName::IPADDRESS != m_base->GetType()) return CPKIFGeneralSubtree::NOT_APPLICABLE;
00221 if(m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 CPKIFBufferPtr base = m_base->ipAddress();
00233 unsigned int baselen = base->GetLength();
00234 unsigned int addrlen = baselen/2;
00235
00236 if(name->GetLength() != addrlen) return CPKIFGeneralSubtree::NO_MATCH;
00237
00238 if(baselen != 32 && baselen != 8) throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered malformed iPAddress");
00239
00240 CPKIFBufferPtr test(new CPKIFBuffer(*name));
00241 const unsigned char * baseBuf = base->GetBuffer();
00242 const unsigned char * maskBuf = baseBuf + addrlen;
00243 unsigned char * testBuf = const_cast<unsigned char *>(test->GetBuffer());
00244
00245 for(unsigned int i = 0; i < addrlen; i++)
00246 {
00247 testBuf[i] &= maskBuf[i];
00248 }
00249
00250 if(!memcmp(baseBuf,testBuf,addrlen)) {
00251 return CPKIFGeneralSubtree::MATCH;
00252 }
00253 return CPKIFGeneralSubtree::NO_MATCH;
00254 }
00255
00265 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtreeImpl::RFC822NameIsInSubtree(const char * name)
00266 {
00267 if(CPKIFGeneralName::RFC822 != m_base->GetType()) return CPKIFGeneralSubtree::NOT_APPLICABLE;
00268 if(m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 string base(m_base->rfc822Name());
00284 string cand(name);
00285
00286
00287
00288 if(!isEmail(cand)) {
00289 throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered malformed rfc822Name");
00290 }
00291
00292
00293 boost::regex_constants::syntax_option_type reflags =
00294 boost::regex_constants::perl | boost::regex_constants::icase;
00295
00296 ostringstream patstream;
00297 patstream << base << "$";
00298 string pattern = escapeDots(patstream.str());
00299 boost::regex re;
00300 boost::smatch what;
00301
00302 re.assign(pattern,reflags);
00303 bool found = boost::regex_search(cand,what,re);
00304
00305
00306
00307 if(!found) return CPKIFGeneralSubtree::NO_MATCH;
00308
00309
00310
00311 if(isEmail(base)) {
00312 if(cand.length() == base.length()) return CPKIFGeneralSubtree::MATCH;
00313 }
00314
00315 int pos;
00316 try {
00317 pos = numeric_cast<int>(what.position());
00318 }catch(bad_numeric_cast &) {
00319 throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered abusively long dns name");
00320 }
00321
00322
00323 if(base[0] != '.') {
00324 if(pos && (cand[pos-1] == '@')) {
00325 return CPKIFGeneralSubtree::MATCH;
00326 }
00327 } else {
00328
00329
00330 if(pos && (cand[pos-1]!='@')) {
00331 return CPKIFGeneralSubtree::MATCH;
00332 }
00333 }
00334
00335 return CPKIFGeneralSubtree::NO_MATCH;
00336 }
00337
00347 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtreeImpl::URINameIsInSubtree(const char * name)
00348 {
00349 if(CPKIFGeneralName::URI != m_base->GetType()) return CPKIFGeneralSubtree::NOT_APPLICABLE;
00350 if(m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00351
00352
00353
00354
00355
00356
00357
00358
00359 string base(m_base->uri());
00360 string cand(name);
00361 cand = getHost(cand);
00362 if(cand == ""){
00363 throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered malformed uriName");
00364 }
00365
00366
00367
00368
00369 boost::regex_constants::syntax_option_type reflags =
00370 boost::regex_constants::perl | boost::regex_constants::icase;
00371
00372 ostringstream patstream;
00373 patstream << base << "$";
00374 string pattern = escapeDots(patstream.str());
00375 boost::regex re;
00376 boost::smatch what;
00377
00378 re.assign(pattern,reflags);
00379 bool found = boost::regex_search(cand,what,re);
00380
00381
00382
00383 if(!found) return CPKIFGeneralSubtree::NO_MATCH;
00384
00385
00386 if(cand.length() == base.length()) return CPKIFGeneralSubtree::MATCH;
00387
00388
00389
00390 int pos;
00391 try {
00392 pos = numeric_cast<int>(what.position());
00393 }catch(bad_numeric_cast &) {
00394 throw CPKIFException(TOOLKIT_ASN, ASN1_DECODE_ERROR, "encountered abusively long dns name");
00395 }
00396 if(pos && cand[pos] == '.') return CPKIFGeneralSubtree::MATCH;
00397
00398 return CPKIFGeneralSubtree::NO_MATCH;
00399 }
00400
00402
00410 CPKIFGeneralSubtree::CPKIFGeneralSubtree()
00411 :m_impl (new CPKIFGeneralSubtreeImpl)
00412 {
00413 m_impl->m_nMax = -1;
00414 m_impl->m_nMin = -1;
00415 CPKIFGeneralNamePtr tmpGN;
00416 m_impl->m_base = tmpGN;
00417 m_impl->m_empty = false;
00418 }
00429 CPKIFGeneralSubtree::CPKIFGeneralSubtree(
00431 const CPKIFBufferPtr& genSubtree)
00432 :m_impl (new CPKIFGeneralSubtreeImpl)
00433 {
00434 m_impl->m_empty = false;
00435 CACASNWRAPPER_CREATE(CACX509V3GeneralSubtree, objPDU);
00436 objPDU.Decode(genSubtree->GetBuffer(), genSubtree->GetLength());
00437
00438 CACASNWRAPPER_CREATE(CACX509V3GeneralName, objPDU2);
00439 ASN1OpenType* data1 = objPDU2.Encode(&(objPDU->base));
00440 CPKIFBufferPtr tmpBuf;
00441 if (data1 != NULL)
00442 {
00443 tmpBuf = CPKIFBufferPtr(new CPKIFBuffer(data1->data, data1->numocts));
00444 delete data1;
00445 }
00446
00447 CPKIFGeneralNamePtr tmpGN(new CPKIFGeneralName(tmpBuf));
00448
00449 m_impl->m_base = tmpGN;
00450
00451 if(objPDU->m.maximumPresent)
00452 m_impl->m_nMax = objPDU->maximum;
00453 else
00454 m_impl->m_nMax = -1;
00455
00456 m_impl->m_nMin = objPDU->minimum;
00457 }
00458
00459
00467 CPKIFGeneralSubtree::~CPKIFGeneralSubtree()
00468 {
00469 if(m_impl)
00470 {
00471 delete m_impl;
00472 m_impl = 0;
00473 }
00474 }
00475
00484 CPKIFGeneralNamePtr CPKIFGeneralSubtree::GetBase() const
00485 {
00486 return m_impl->m_base;
00487 }
00495 int CPKIFGeneralSubtree::GetMin() const
00496 {
00497 return m_impl->m_nMin;
00498 }
00506 int CPKIFGeneralSubtree::GetMax() const
00507 {
00508 return m_impl->m_nMax;
00509 }
00510
00518 void CPKIFGeneralSubtree::SetBase(CPKIFGeneralNamePtr gn)
00519 {
00520 m_impl->m_base = gn;
00521 }
00529 void CPKIFGeneralSubtree::SetMin(int n)
00530 {
00531 m_impl->m_nMin = n;
00532 }
00540 void CPKIFGeneralSubtree::SetMax(int n)
00541 {
00542 m_impl->m_nMax = n;
00543 }
00544
00556 bool CPKIFGeneralSubtree::operator==(
00558 const CPKIFGeneralSubtree& rhs)
00559 {
00560 if(!(*m_impl->m_base == *rhs.m_impl->m_base))
00561 return false;
00562
00563 if(m_impl->m_nMin != rhs.m_impl->m_nMin)
00564 return false;
00565
00566 if(m_impl->m_nMax != rhs.m_impl->m_nMax)
00567 return false;
00568
00569
00570
00571
00572
00573
00574 return true;
00575 }
00576
00590 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtree::IsInSubtree(
00592 const CPKIFNamePtr& subject)const
00593 {
00594
00595
00596 if(!m_impl->m_base || -1 == m_impl->m_nMin)
00597 throw CPKIFException(TOOLKIT_ASN,COMMON_NOT_INITIALIZED,"An attempt was made to use an uninitialized GeneralSubtree");
00598 if(!subject)
00599 throw CPKIFException(TOOLKIT_X509_ASN, COMMON_INVALID_INPUT, "CPKIFGeneralSubtree::IsInSubtree called with an invalid CPKIFName object");
00600
00601 switch(m_impl->m_base->GetType()) {
00602 case CPKIFGeneralName::DIRECTORYNAME:
00603 {
00604
00605
00606 if(m_impl->m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00607 CPKIFNamePtr subtreeName = m_impl->m_base->directoryName();
00608 if(!subtreeName->DescendedFrom(*subject) && !(*subtreeName == *subject))
00609 return NO_MATCH;
00610
00611 int diff = subject->RDNCount() - subtreeName->RDNCount();
00612 if(-1 != m_impl->m_nMin && diff < m_impl->m_nMin)
00613 return NO_MATCH;
00614
00615 if(-1 != m_impl->m_nMax && diff > m_impl->m_nMax)
00616 return NO_MATCH;
00617
00618 return MATCH;
00619 break;
00620 }
00621
00622
00623 case CPKIFGeneralName::RFC822:
00624 {
00625 if(!erdnre_init) {
00626 erdnre.assign(erdnpat,boost::regex_constants::perl);
00627 erdnre_init = true;
00628 }
00629 vector<string>rdns;
00630 subject->GetRDNs(rdns);
00631 vector<string>::iterator end = rdns.end();
00632 vector<string>::iterator pos;
00633 CPKIFGeneralSubtree::MatchState emailState = NOT_APPLICABLE;
00634
00635
00636
00637 for(pos = rdns.begin();
00638 emailState != NO_MATCH && pos != end;
00639 ++pos)
00640 {
00641 boost::smatch what;
00642 bool found = boost::regex_match((*pos),what,erdnre);
00643 if(found) {
00644
00645
00646 if(m_impl->m_empty) return CPKIFGeneralSubtree::NO_MATCH;
00647 string email;
00648 email.assign(what[1].first,what[1].second);
00649 CPKIFGeneralSubtree::MatchState tmpState = m_impl->RFC822NameIsInSubtree(email.c_str());
00650 if(emailState == NOT_APPLICABLE)
00651 emailState = tmpState;
00652 }
00653
00654 }
00655 return emailState;
00656 break;
00657 }
00658
00659 default:
00660 throw CPKIFException(TOOLKIT_ASN, -1, "Unsupported name form");
00661 break;
00662 }
00663 return NO_MATCH;
00664 }
00665
00680 CPKIFGeneralSubtree::MatchState CPKIFGeneralSubtree::IsInSubtree(
00682 const CPKIFGeneralNamePtr & name
00683 )const
00684 {
00685
00686
00687 if(!m_impl->m_base || -1 == m_impl->m_nMin)
00688 throw CPKIFException(TOOLKIT_ASN,COMMON_NOT_INITIALIZED,"An attempt was made to use an uninitialized GeneralSubtree");
00689 if(!name)
00690 throw CPKIFException(TOOLKIT_X509_ASN, COMMON_INVALID_INPUT, "CPKIFGeneralSubtree::IsInSubtree called with an invalid CPKIFGeneralName object");
00691
00692 if(name->GetType() != m_impl->m_base->GetType())
00693 return NOT_APPLICABLE;
00694
00695 switch(name->GetType())
00696 {
00697 case CPKIFGeneralName::DIRECTORYNAME:
00698 return IsInSubtree(name->directoryName());
00699 break;
00700 case CPKIFGeneralName::DNSNAME:
00701 return m_impl->DNSNameIsInSubtree(name->dnsName());
00702 break;
00703 case CPKIFGeneralName::IPADDRESS:
00704 return m_impl->IPAddressIsInSubtree(name->ipAddress());
00705 break;
00706 case CPKIFGeneralName::RFC822:
00707 return m_impl->RFC822NameIsInSubtree(name->rfc822Name());
00708 break;
00709 case CPKIFGeneralName::URI:
00710 return m_impl->URINameIsInSubtree(name->uri());
00711 break;
00712 default:
00713 throw CPKIFException(TOOLKIT_ASN,-1,"Unsupported name form");
00714 }
00715 return NO_MATCH;
00716 }
00717
00727 bool CPKIFGeneralSubtree::IsSupported(
00729 CPKIFGeneralName::GENNAMETYPE type)
00730 {
00731 switch(type)
00732 {
00733 case CPKIFGeneralName::DIRECTORYNAME:
00734 case CPKIFGeneralName::DNSNAME:
00735 case CPKIFGeneralName::IPADDRESS:
00736 case CPKIFGeneralName::RFC822:
00737 case CPKIFGeneralName::URI:
00738 return true;
00739 break;
00740 default:
00741 break;
00742 }
00743 return false;
00744 }
00745
00756 void CPKIFGeneralSubtree::SetEmpty()
00757 {
00758 m_impl->m_empty = true;
00759 }
00760
00769 CPKIFGeneralSubtree * CPKIFGeneralSubtree::ShallowCopy()
00770 {
00771 CPKIFGeneralSubtree * tmp = new CPKIFGeneralSubtree();
00772 tmp->m_impl->m_base = m_impl->m_base;
00773 tmp->m_impl->m_nMax = m_impl->m_nMax;
00774 tmp->m_impl->m_nMin = m_impl->m_nMin;
00775 tmp->m_impl->m_empty = m_impl->m_empty;
00776 return tmp;
00777 }