00001
00002
00003 const char *XrdCryptoX509ChainCVSID = "$Id: XrdCryptoX509Chain.cc 33678 2010-06-01 08:19:53Z ganis $";
00004
00005
00006
00007
00008
00009
00010
00011 #include <time.h>
00012 #include <string.h>
00013
00014 #include <XrdCrypto/XrdCryptoX509Chain.hh>
00015 #include <XrdCrypto/XrdCryptoTrace.hh>
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #define LOCDUMP(y) { cerr << epname << ":" << y << endl; }
00028
00029
00030 static const char *X509ChainErrStr[] = {
00031 "no error condition occured",
00032 "chain is inconsistent",
00033 "size exceeds max allowed depth",
00034 "invalid or missing CA",
00035 "certificate missing",
00036 "unexpected certificate type",
00037 "names invalid or missing",
00038 "certificate has been revoked",
00039 "certificate expired",
00040 "extension not found",
00041 "signature verification failed",
00042 "issuer had no signing rights",
00043 "CA issued by another CA"
00044 };
00045
00046
00047 XrdCryptoX509Chain::XrdCryptoX509Chain(XrdCryptoX509 *c)
00048 {
00049
00050
00051 previous = 0;
00052 current = 0;
00053 begin = 0;
00054 end = 0;
00055 size = 0;
00056 lastError = "";
00057 caname = "";
00058 eecname = "";
00059 cahash = "";
00060 eechash = "";
00061 statusCA = kUnknown;
00062
00063 if (c) {
00064 XrdCryptoX509ChainNode *f = new XrdCryptoX509ChainNode(c,0);
00065 current = begin = end = f;
00066 size++;
00067
00068
00069 if (c->type == XrdCryptoX509::kCA) {
00070 caname = c->Subject();
00071 cahash = c->SubjectHash();
00072 EX509ChainErr ecode = kNone;
00073 if (!Verify(ecode, "CA: ",XrdCryptoX509::kCA, 0, c, c))
00074 statusCA = kInvalid;
00075 else
00076 statusCA = kValid;
00077 }
00078 }
00079 }
00080
00081
00082 XrdCryptoX509Chain::XrdCryptoX509Chain(XrdCryptoX509Chain *ch)
00083 {
00084
00085
00086 previous = 0;
00087 current = 0;
00088 begin = 0;
00089 end = 0;
00090 size = 0;
00091 lastError = ch->LastError();
00092 caname = ch->CAname();
00093 eecname = ch->EECname();
00094 cahash = ch->CAhash();
00095 eechash = ch->EEChash();
00096 statusCA = ch->StatusCA();
00097
00098 XrdCryptoX509 *c = ch->Begin();
00099 while (c) {
00100 XrdCryptoX509ChainNode *nc = new XrdCryptoX509ChainNode(c,0);
00101 if (!begin)
00102 begin = nc;
00103 if (end)
00104 end->SetNext(nc);
00105 end = nc;
00106 size++;
00107
00108 c = ch->Next();
00109 }
00110 }
00111
00112
00113 XrdCryptoX509Chain::~XrdCryptoX509Chain()
00114 {
00115
00116
00117 XrdCryptoX509ChainNode *n = 0;
00118 XrdCryptoX509ChainNode *c = begin;
00119 while (c) {
00120 n = c->Next();
00121 delete (c);
00122 c = n;
00123 }
00124 }
00125
00126
00127 void XrdCryptoX509Chain::Cleanup(bool keepCA)
00128 {
00129
00130
00131
00132 XrdCryptoX509ChainNode *n = 0;
00133 XrdCryptoX509ChainNode *c = begin;
00134 while (c) {
00135 n = c->Next();
00136 if (c->Cert() &&
00137 (!keepCA || (c->Cert()->type != XrdCryptoX509::kCA)))
00138 delete (c->Cert());
00139 delete (c);
00140 c = n;
00141 }
00142
00143
00144 previous = 0;
00145 current = 0;
00146 begin = 0;
00147 end = 0;
00148 size = 0;
00149 lastError = "";
00150 caname = "";
00151 eecname = "";
00152 cahash = "";
00153 eechash = "";
00154 statusCA = kUnknown;
00155 }
00156
00157
00158 bool XrdCryptoX509Chain::CheckCA(bool checkselfsigned)
00159 {
00160
00161
00162
00163
00164
00165
00166
00167 XrdCryptoX509 *xc = 0;
00168 XrdCryptoX509ChainNode *n = 0;
00169 XrdCryptoX509ChainNode *c = begin;
00170 XrdCryptoX509ChainNode *p = 0;
00171 lastError = "";
00172 while (c) {
00173 n = c->Next();
00174 xc = c->Cert();
00175 if (xc && xc->type == XrdCryptoX509::kCA) {
00176 caname = xc->Subject();
00177 cahash = xc->SubjectHash();
00178 EX509ChainErr ecode = kNone;
00179 bool CAok = Verify(ecode, "CA: ",XrdCryptoX509::kCA, 0, xc, xc);
00180 if (!CAok && (ecode != kVerifyFail || checkselfsigned)) {
00181 statusCA = kInvalid;
00182 lastError += X509ChainError(ecode);
00183 } else {
00184 statusCA = kValid;
00185 if (p) {
00186
00187 p->SetNext(c->Next());
00188 c->SetNext(begin);
00189 if (end == c) end = p;
00190 begin = c;
00191 }
00192 return 1;
00193 }
00194 }
00195 p = c;
00196 c = n;
00197 }
00198
00199
00200 return 0;
00201 }
00202
00203
00204 const char *XrdCryptoX509Chain::X509ChainError(EX509ChainErr e)
00205 {
00206
00207
00208 return X509ChainErrStr[e];
00209 }
00210
00211
00212 XrdCryptoX509ChainNode *XrdCryptoX509Chain::Find(XrdCryptoX509 *c)
00213 {
00214
00215
00216 XrdCryptoX509ChainNode *nd = begin;
00217 for (; nd; nd = nd->Next()) {
00218 if (nd->Cert() == c)
00219 return nd;
00220 }
00221 return (XrdCryptoX509ChainNode *)0;
00222 }
00223
00224
00225 void XrdCryptoX509Chain::PutInFront(XrdCryptoX509 *c)
00226 {
00227
00228
00229
00230 if (!Find(c)) {
00231 XrdCryptoX509ChainNode *nc = new XrdCryptoX509ChainNode(c,begin);
00232 begin = nc;
00233 if (!end)
00234 end = nc;
00235 size++;
00236 }
00237 }
00238
00239
00240 void XrdCryptoX509Chain::InsertAfter(XrdCryptoX509 *c, XrdCryptoX509 *cp)
00241 {
00242
00243
00244
00245 XrdCryptoX509ChainNode *nc = Find(c);
00246 XrdCryptoX509ChainNode *ncp = Find(cp);
00247 if (ncp) {
00248
00249 if (!nc) {
00250 nc = new XrdCryptoX509ChainNode(c,ncp->Next());
00251 size++;
00252 }
00253
00254 ncp->SetNext(nc);
00255 if (end == ncp)
00256 end = nc;
00257
00258 } else {
00259
00260
00261 if (!nc)
00262 PushBack(c);
00263 }
00264 }
00265
00266
00267 void XrdCryptoX509Chain::PushBack(XrdCryptoX509 *c)
00268 {
00269
00270
00271
00272 if (!Find(c)) {
00273 XrdCryptoX509ChainNode *nc = new XrdCryptoX509ChainNode(c,0);
00274 if (!begin)
00275 begin = nc;
00276 if (end)
00277 end->SetNext(nc);
00278 end = nc;
00279 size++;
00280 }
00281 }
00282
00283
00284 void XrdCryptoX509Chain::Remove(XrdCryptoX509 *c)
00285 {
00286
00287
00288 XrdCryptoX509ChainNode *curr = current;
00289 XrdCryptoX509ChainNode *prev = previous;
00290
00291 if (!curr || curr->Cert() != c || (prev && curr != prev->Next())) {
00292
00293 curr = begin;
00294 prev = 0;
00295 for (; curr; curr = curr->Next()) {
00296 if (curr->Cert() == c)
00297 break;
00298 prev = curr;
00299 }
00300 }
00301
00302
00303 if (!curr)
00304 return;
00305
00306
00307
00308 if (c->type == XrdCryptoX509::kCA && curr == begin) {
00309
00310
00311 statusCA = kUnknown;
00312 caname = "";
00313 cahash = "";
00314 }
00315
00316
00317 if (prev) {
00318 current = curr->Next();
00319 prev->SetNext(current);
00320 previous = curr;
00321 } else if (curr == begin) {
00322
00323 current = curr->Next();
00324 begin = current;
00325 previous = 0;
00326 }
00327
00328
00329 delete curr;
00330 size--;
00331 }
00332
00333
00334 XrdCryptoX509 *XrdCryptoX509Chain::Begin()
00335 {
00336
00337
00338 previous = 0;
00339 current = begin;
00340 if (current)
00341 return current->Cert();
00342 return (XrdCryptoX509 *)0;
00343 }
00344
00345
00346 XrdCryptoX509 *XrdCryptoX509Chain::Next()
00347 {
00348
00349
00350 previous = current;
00351 if (current) {
00352 current = current->Next();
00353 if (current)
00354 return current->Cert();
00355 }
00356 return (XrdCryptoX509 *)0;
00357 }
00358
00359
00360 XrdCryptoX509 *XrdCryptoX509Chain::SearchByIssuer(const char *issuer,
00361 ESearchMode mode)
00362 {
00363
00364
00365
00366 XrdCryptoX509ChainNode *cn = FindIssuer(issuer, mode);
00367
00368
00369 return ((cn) ? cn->Cert() : (XrdCryptoX509 *)0);
00370 }
00371
00372
00373 XrdCryptoX509 *XrdCryptoX509Chain::SearchBySubject(const char *subject,
00374 ESearchMode mode)
00375 {
00376
00377
00378
00379 XrdCryptoX509ChainNode *cn = FindSubject(subject, mode);
00380
00381
00382 return ((cn) ? cn->Cert() : (XrdCryptoX509 *)0);
00383
00384 }
00385
00386
00387 XrdCryptoX509ChainNode *XrdCryptoX509Chain::FindIssuer(const char *issuer,
00388 ESearchMode mode, XrdCryptoX509ChainNode **prev)
00389 {
00390
00391
00392
00393
00394 if (!issuer)
00395 return (XrdCryptoX509ChainNode *)0;
00396
00397 XrdCryptoX509ChainNode *cp = 0;
00398 XrdCryptoX509ChainNode *n = 0;
00399 XrdCryptoX509ChainNode *cn = begin;
00400 XrdCryptoX509 *c = 0;
00401 while (cn) {
00402 n = cn->Next();
00403 c = cn->Cert();
00404 const char *pi = c->Issuer();
00405 if (c && pi) {
00406 if (mode == kExact) {
00407 if (!strcmp(pi, issuer))
00408 break;
00409 } else if (mode == kBegin) {
00410 if (strstr(pi, issuer) == c->Issuer())
00411 break;
00412 } else if (mode == kEnd) {
00413 int ibeg = strlen(pi) - strlen(issuer);
00414 if (!strcmp(pi + ibeg, issuer))
00415 break;
00416 }
00417 }
00418 c = 0;
00419 cp = cn;
00420 cn = n;
00421 }
00422
00423 if (prev)
00424 *prev = (cn) ? cp : 0;
00425
00426
00427 return ((cn) ? cn : (XrdCryptoX509ChainNode *)0);
00428 }
00429
00430
00431 XrdCryptoX509ChainNode *XrdCryptoX509Chain::FindSubject(const char *subject,
00432 ESearchMode mode, XrdCryptoX509ChainNode **prev)
00433 {
00434
00435
00436
00437
00438 if (!subject)
00439 return (XrdCryptoX509ChainNode *)0;
00440
00441 XrdCryptoX509ChainNode *cp = 0;
00442 XrdCryptoX509ChainNode *n = 0;
00443 XrdCryptoX509ChainNode *cn = begin;
00444 XrdCryptoX509 *c = 0;
00445 while (cn) {
00446 n = cn->Next();
00447 c = cn->Cert();
00448 const char *ps = c ? c->Subject() : 0;
00449 if (c && ps) {
00450 if (mode == kExact) {
00451 if (!strcmp(ps, subject))
00452 break;
00453 } else if (mode == kBegin) {
00454 if (strstr(ps, subject) == ps)
00455 break;
00456 } else if (mode == kEnd) {
00457 int sbeg = strlen(ps) - strlen(subject);
00458 if (!strcmp(ps + sbeg, subject))
00459 break;
00460 }
00461 }
00462 c = 0;
00463 cp = cn;
00464 cn = n;
00465 }
00466
00467 if (prev)
00468 *prev = (cn) ? cp : 0;
00469
00470
00471 return ((cn) ? cn : (XrdCryptoX509ChainNode *)0);
00472 }
00473
00474
00475 void XrdCryptoX509Chain::Dump()
00476 {
00477
00478 EPNAME("X509Chain::Dump");
00479
00480 LOCDUMP("//------------------Dumping X509 chain content ------------------//");
00481 LOCDUMP("//");
00482 LOCDUMP("// Chain instance: "<<this);
00483 LOCDUMP("//");
00484 LOCDUMP("// Number of certificates: "<<Size());
00485 LOCDUMP("//");
00486 if (CAname()) {
00487 LOCDUMP("// CA: "<<CAname());
00488 } else {
00489 LOCDUMP("// CA: absent");
00490 }
00491 if (EECname()) {
00492 LOCDUMP("// EEC: "<<EECname());
00493 } else {
00494 LOCDUMP("// EEC: absent");
00495 }
00496 LOCDUMP("//");
00497 XrdCryptoX509ChainNode *n = 0;
00498 XrdCryptoX509ChainNode *c = begin;
00499 while (c) {
00500 n = c->Next();
00501 if (c->Cert()) {
00502 LOCDUMP("// Issuer: "<<c->Cert()->IssuerHash()<<
00503 " Subject: "<<c->Cert()->SubjectHash()<<
00504 " Type: "<<c->Cert()->Type());
00505 }
00506 c = n;
00507 }
00508 LOCDUMP("//");
00509 LOCDUMP("//---------------------------- END ------------------------------//")
00510 }
00511
00512
00513 int XrdCryptoX509Chain::Reorder()
00514 {
00515
00516
00517
00518 EPNAME("X509Chain::Reorder");
00519
00520 if (size < 2) {
00521 DEBUG("Nothing to reorder (size: "<<size<<")");
00522 return 0;
00523 }
00524
00525
00526 XrdCryptoX509ChainNode *nc = 0, *np = 0, *nn = 0, *nr = 0, *npp = 0;
00527
00528
00529 nr = begin;
00530 np = nr;
00531 while (nr) {
00532
00533 if (!(nn = FindSubject(nr->Cert()->Issuer(),kExact,&npp)) ||
00534 nn == nr)
00535 break;
00536 np = nr;
00537 nr = nr->Next();
00538 }
00539
00540
00541 if (nr != begin) {
00542 np->SetNext(nr->Next());
00543 nr->SetNext(begin);
00544 if (end == nr)
00545 end = np;
00546 begin = nr;
00547
00548 if (nr->Cert()->type != XrdCryptoX509::kCA) {
00549 statusCA = kAbsent;
00550 } else if (caname.length() <= 0) {
00551
00552
00553 caname = nr->Cert()->Subject();
00554 cahash = nr->Cert()->SubjectHash();
00555 statusCA = kUnknown;
00556 }
00557 }
00558
00559 int left = size-1;
00560 np = begin;
00561 while (np) {
00562 if (np->Cert()) {
00563 const char *pi = np->Cert()->Subject();
00564
00565 if (np->Cert()->type == XrdCryptoX509::kEEC && eecname.length() <= 0) {
00566 eecname = pi;
00567 eechash = np->Cert()->SubjectHash();
00568 }
00569 npp = np;
00570 nc = np->Next();
00571 while (nc) {
00572 if (nc->Cert() && !strcmp(pi, nc->Cert()->Issuer())) {
00573 left--;
00574 if (npp != np) {
00575 npp->SetNext(nc->Next());
00576 nc->SetNext(np->Next());
00577 np->SetNext(nc);
00578 if (nc == end)
00579 end = npp;
00580 }
00581 break;
00582 }
00583 npp = nc;
00584 nc = nc->Next();
00585 }
00586 }
00587 np = np->Next();
00588 }
00589
00590
00591 if (left > 0) {
00592 DEBUG("Inconsistency found: "<<left<<
00593 " certificates could not be correctly enchained!");
00594 return -1;
00595 }
00596
00597
00598 return 0;
00599 }
00600
00601
00602 bool XrdCryptoX509Chain::Verify(EX509ChainErr &errcode, x509ChainVerifyOpt_t *vopt)
00603 {
00604
00605 EPNAME("X509Chain::Verify");
00606 errcode = kNone;
00607
00608
00609 if (size < 1) {
00610 DEBUG("Nothing to verify (size: "<<size<<")");
00611 return 0;
00612 }
00613
00614
00615
00616 if (Reorder() != 0) {
00617 errcode = kInconsistent;
00618 lastError = ":";
00619 lastError += X509ChainError(errcode);
00620 return 0;
00621 }
00622
00623
00624
00625 int when = (vopt) ? vopt->when : (int)time(0);
00626 int plen = (vopt) ? vopt->pathlen : -1;
00627 bool chkss = (vopt) ? (vopt->opt & kOptsCheckSelfSigned) : 1;
00628
00629
00630
00631 if (plen > -1 && plen < size) {
00632 errcode = kTooMany;
00633 lastError = "checking path depth: ";
00634 lastError += X509ChainError(errcode);
00635 }
00636
00637
00638
00639
00640 if (!CheckCA(chkss)) {
00641 errcode = kNoCA;
00642 lastError = X509ChainError(errcode);
00643 return 0;
00644 }
00645
00646
00647
00648 XrdCryptoX509ChainNode *node = begin;
00649 XrdCryptoX509 *xsig = node->Cert();
00650 XrdCryptoX509 *xcer = 0;
00651 node = node->Next();
00652 while (node) {
00653
00654
00655 xcer = node->Cert();
00656
00657
00658 if (!Verify(errcode, "cert: ", XrdCryptoX509::kUnknown, when, xcer, xsig))
00659 return 0;
00660
00661
00662 xsig = xcer;
00663 node = node->Next();
00664 }
00665
00666
00667 return 1;
00668 }
00669
00670
00671 int XrdCryptoX509Chain::CheckValidity(bool outatfirst, int when)
00672 {
00673
00674
00675
00676
00677 EPNAME("X509Chain::CheckValidity");
00678 int ninv = 0;
00679
00680
00681 if (size < 1) {
00682 DEBUG("Nothing to verify (size: "<<size<<")");
00683 return ninv;
00684 }
00685
00686
00687 XrdCryptoX509ChainNode *nc = begin;
00688 while (nc) {
00689
00690 XrdCryptoX509 *c = nc->Cert();
00691 if (c) {
00692 if (!(c->IsValid(when))) {
00693 ninv++;
00694 DEBUG("invalid certificate found");
00695 if (outatfirst)
00696 return ninv;
00697 }
00698 } else {
00699 ninv++;
00700 DEBUG("found node without certificate");
00701 if (outatfirst)
00702 return ninv;
00703 }
00704
00705 nc = nc->Next();
00706 }
00707
00708
00709 return ninv;
00710 }
00711
00712
00713 bool XrdCryptoX509Chain::Verify(EX509ChainErr &errcode, const char *msg,
00714 XrdCryptoX509::EX509Type type, int when,
00715 XrdCryptoX509 *xcer, XrdCryptoX509 *xsig,
00716 XrdCryptoX509Crl *crl)
00717 {
00718
00719
00720
00721 if (!xcer) {
00722 errcode = kNoCertificate;
00723 lastError = msg;
00724 lastError += X509ChainError(errcode);
00725 return 0;
00726 }
00727
00728
00729 if (type != XrdCryptoX509::kUnknown && xcer->type != type) {
00730 errcode = kInvalidType;
00731 lastError = msg;
00732 lastError += X509ChainError(errcode);
00733 return 0;
00734 }
00735
00736
00737 if (crl) {
00738
00739 XrdOucString sn = xcer->SerialNumberString();
00740 if (crl->IsRevoked(sn.c_str(), when)) {
00741 errcode = kRevoked;
00742 lastError = msg;
00743 lastError += X509ChainError(errcode);
00744 return 0;
00745 }
00746 }
00747
00748
00749 if (when >= 0 && !(xcer->IsValid(when))) {
00750 errcode = kExpired;
00751 lastError = msg;
00752 lastError += X509ChainError(errcode);
00753 return 0;
00754 }
00755
00756
00757 if (!xsig || !(xcer->Verify(xsig))) {
00758 errcode = kVerifyFail;
00759 lastError = msg;
00760 lastError += X509ChainError(errcode);
00761 return 0;
00762 }
00763
00764
00765 return 1;
00766 }
00767
00768
00769 const char *XrdCryptoX509Chain::CAname()
00770 {
00771
00772 EPNAME("X509Chain::CAname");
00773
00774
00775 if (caname.length() <= 0 && statusCA == kUnknown) {
00776
00777 if (!CheckCA()) {
00778 DEBUG("CA not found in chain");
00779 return (const char *)0;
00780 }
00781 }
00782
00783
00784 return (caname.length() > 0) ? caname.c_str() : (const char *)0;
00785 }
00786
00787
00788 const char *XrdCryptoX509Chain::EECname()
00789 {
00790
00791 EPNAME("X509Chain::EECname");
00792
00793
00794 if (eecname.length() <= 0) {
00795
00796 XrdCryptoX509ChainNode *c = begin;
00797 while (c) {
00798 if (c->Cert()->type == XrdCryptoX509::kEEC) {
00799 eecname = c->Cert()->Subject();
00800 break;
00801 }
00802 c = c->Next();
00803 }
00804 if (eecname.length() <= 0) {
00805 DEBUG("EEC not found in chain");
00806 return (const char *)0;
00807 }
00808 }
00809
00810
00811 return (eecname.length() > 0) ? eecname.c_str() : (const char *)0;
00812 }
00813
00814
00815 const char *XrdCryptoX509Chain::CAhash()
00816 {
00817
00818 EPNAME("X509Chain::CAhash");
00819
00820
00821 if (cahash.length() <= 0 && statusCA == kUnknown) {
00822
00823 if (!CheckCA()) {
00824 DEBUG("CA not found in chain");
00825 return (const char *)0;
00826 }
00827 }
00828
00829
00830 return (cahash.length() > 0) ? cahash.c_str() : (const char *)0;
00831 }
00832
00833
00834 const char *XrdCryptoX509Chain::EEChash()
00835 {
00836
00837 EPNAME("X509Chain::EEChash");
00838
00839
00840 if (eechash.length() <= 0) {
00841
00842 XrdCryptoX509ChainNode *c = begin;
00843 while (c) {
00844 if (c->Cert()->type == XrdCryptoX509::kEEC) {
00845 eechash = c->Cert()->SubjectHash();
00846 break;
00847 }
00848 c = c->Next();
00849 }
00850 if (eechash.length() <= 0) {
00851 DEBUG("EEC not found in chain");
00852 return (const char *)0;
00853 }
00854 }
00855
00856
00857 return (eechash.length() > 0) ? eechash.c_str() : (const char *)0;
00858 }