XRootD
Loading...
Searching...
No Matches
XrdCryptoX509Chain.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C r y p t o X 5 0 9 C h a i n . c c */
4/* */
5/* (c) 2005 G. Ganis, CERN */
6/* */
7/* This file is part of the XRootD software suite. */
8/* */
9/* XRootD is free software: you can redistribute it and/or modify it under */
10/* the terms of the GNU Lesser General Public License as published by the */
11/* Free Software Foundation, either version 3 of the License, or (at your */
12/* option) any later version. */
13/* */
14/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
15/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
16/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
17/* License for more details. */
18/* */
19/* You should have received a copy of the GNU Lesser General Public License */
20/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
21/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
22/* */
23/* The copyright holder's institutional names and contributor's names may not */
24/* be used to endorse or promote products derived from this software without */
25/* specific prior written permission of the institution or contributor. */
26/* */
27/******************************************************************************/
28#include <ctime>
29#include <cstring>
30
33
34// ---------------------------------------------------------------------------//
35// //
36// XrdCryptoX509Chain //
37// //
38// Light single-linked list for managing stacks of XrdCryptoX509* objects //
39// //
40// ---------------------------------------------------------------------------//
41
42// For test dumps, to avoid interfering with the trace mutex
43#define LOCDUMP(y) { std::cerr << epname << ":" << y << std::endl; }
44
45// Description of errors
46static const char *X509ChainErrStr[] = {
47 "no error condition occurred", // 0
48 "chain is inconsistent", // 1
49 "size exceeds max allowed depth", // 2
50 "invalid or missing CA", // 3
51 "certificate missing", // 4
52 "unexpected certificate type", // 5
53 "names invalid or missing", // 6
54 "certificate has been revoked", // 7
55 "certificate expired", // 8
56 "extension not found", // 9
57 "signature verification failed", // 10
58 "issuer had no signing rights", // 11
59 "CA issued by another CA", // 12
60 "invalid or missing EEC", // 13
61 "too many EEC", // 14
62 "invalid proxy" // 15
63};
64
65//___________________________________________________________________________
67{
68 // Constructor
69
70 previous = 0;
71 current = 0;
72 begin = 0;
73 end = 0;
74 effca = 0;
75 size = 0;
76 lastError = "";
77 caname = "";
78 eecname = "";
79 cahash = "";
80 eechash = "";
82
83 if (c) {
85 current = begin = end = f;
86 size++;
87 //
88 // If CA verify it and save result
89 if (c->type == XrdCryptoX509::kCA) {
90 caname = c->Subject();
91 cahash = c->SubjectHash();
92 EX509ChainErr ecode = kNone;
93 if (!Verify(ecode, "CA: ",XrdCryptoX509::kCA, 0, c, c))
95 else
97 }
98 // Search for the effective CA
100 }
101}
102
103//___________________________________________________________________________
105{
106 // Copy constructor
107
108 previous = 0;
109 current = 0;
110 begin = 0;
111 end = 0;
112 effca = 0;
113 size = 0;
114 lastError = ch->LastError();
115 caname = ch->CAname();
116 eecname = ch->EECname();
117 cahash = ch->CAhash();
118 eechash = ch->EEChash();
119 statusCA = ch->StatusCA();
120
121 XrdCryptoX509 *c = ch->Begin();
122 while (c) {
124 if (!begin)
125 begin = nc;
126 if (end)
127 end->SetNext(nc);
128 end = nc;
129 if (c == ch->EffCA()) effca = nc;
130 size++;
131 // Go to Next
132 c = ch->Next();
133 }
134}
135
136//___________________________________________________________________________
138{
139 // Destructor
140
143 while (c) {
144 n = c->Next();
145 delete (c);
146 c = n;
147 }
148}
149
150//___________________________________________________________________________
152{
153 // Destructs content of nodes AND their content
154 // If keepCA is true, the top CA is kept
155
158 while (c) {
159 n = c->Next();
160 if (c->Cert() &&
161 (!keepCA || (c->Cert()->type != XrdCryptoX509::kCA)))
162 delete (c->Cert());
163 delete (c);
164 c = n;
165 }
166
167 // Reset
168 previous = 0;
169 current = 0;
170 begin = 0;
171 end = 0;
172 effca = 0;
173 size = 0;
174 lastError = "";
175 caname = "";
176 eecname = "";
177 cahash = "";
178 eechash = "";
180}
181
182//___________________________________________________________________________
183bool XrdCryptoX509Chain::CheckCA(bool checkselfsigned)
184{
185 // Search the list for a valid CA and set it at top.
186 // Search stops when a valid CA is found; an invalid CA is flagged.
187 // A second CA is always ignored.
188 // Signature check failures are accepted if 'checkselfsigned' is false.
189 // Return 1 if found, 0 otherwise; lastError is filled with the reason of
190 // failure, if any.
191
192 XrdCryptoX509 *xc = 0;
196 lastError = "";
197 while (c) {
198 n = c->Next();
199 xc = c->Cert();
200 if (xc && xc->type == XrdCryptoX509::kCA) {
201 caname = xc->Subject();
202 cahash = xc->SubjectHash();
203 EX509ChainErr ecode = kNone;
204 bool CAok = Verify(ecode, "CA: ",XrdCryptoX509::kCA, 0, xc, xc);
205 if (!CAok && (ecode != kVerifyFail || checkselfsigned)) {
207 lastError += X509ChainError(ecode);
208 } else {
210 if (p) {
211 // Move at top
212 p->SetNext(c->Next());
213 c->SetNext(begin);
214 if (end == c) end = p;
215 begin = c;
216 }
217 return 1;
218 }
219 }
220 p = c; // Previous node
221 c = n;
222 }
223
224 // Found nothing
225 return 0;
226}
227
228//___________________________________________________________________________
230{
231 // Return error string
232
233 return X509ChainErrStr[e];
234}
235
236//___________________________________________________________________________
238{
239 // Find node containing bucket b
240
242 for (; nd; nd = nd->Next()) {
243 if (nd->Cert() == c)
244 return nd;
245 }
246 return (XrdCryptoX509ChainNode *)0;
247}
248
249//___________________________________________________________________________
251{
252 // Add at the beginning of the list
253 // Check to avoid duplicates
254
255 if (!Find(c)) {
257 begin = nc;
258 if (!end)
259 end = nc;
260 size++;
261 }
262
263 // Search for the effective CA (the last one, in case of subCAs)
265}
266
267//___________________________________________________________________________
269{
270 // Add or move certificate 'c' after certificate 'cp'; if 'cp' is not
271 // in the list, push-back
272
274 XrdCryptoX509ChainNode *ncp = Find(cp);
275 if (ncp) {
276 // Create a new node, if not there
277 if (!nc) {
278 nc = new XrdCryptoX509ChainNode(c,ncp->Next());
279 size++;
280 }
281 // Update pointers
282 ncp->SetNext(nc);
283 if (end == ncp)
284 end = nc;
285
286 } else {
287 // Reference certificate not in the list
288 // If new, add in last position; otherwise leave it where it is
289 if (!nc)
290 PushBack(c);
291 }
292
293 // Search for the effective CA (the last one, in case of subCAs)
295}
296
297//___________________________________________________________________________
299{
300 // Add at the end of the list
301 // Check to avoid duplicates
302
303 if (!Find(c)) {
305 if (!begin)
306 begin = nc;
307 if (end)
308 end->SetNext(nc);
309 end = nc;
310 size++;
311 } else if (c) {
312 delete c;
313 }
314
315 // Search for the effective CA (the last one, in case of subCAs)
317}
318
319//___________________________________________________________________________
321{
322 // Remove node containing bucket b
323
326
327 if (!curr || curr->Cert() != c || (prev && curr != prev->Next())) {
328 // We need first to find the address
329 curr = begin;
330 prev = 0;
331 for (; curr; curr = curr->Next()) {
332 if (curr->Cert() == c)
333 break;
334 prev = curr;
335 }
336 }
337
338 // The certificate is not in the list
339 if (!curr)
340 return;
341
342 //
343 // If this was the top CA update the related information
344 if (c->type == XrdCryptoX509::kCA && curr == begin) {
345 // There may be other CAs in the chain, but we will
346 // check when needed
348 caname = "";
349 cahash = "";
350 }
351
352 // Now we have all the information to remove
353 if (prev) {
354 if (curr != end) {
355 current = curr->Next();
356 prev->SetNext(current);
357 previous = prev;
358 } else {
359 end = prev;
360 previous = end;
361 current = 0;
362 prev->SetNext(current);
363 }
364 } else if (curr == begin) {
365 // First buffer
366 current = curr->Next();
367 begin = current;
368 previous = 0;
369 }
370
371 // Cleanup and update size
372 delete curr;
373 size--;
374
375 // Search for the effective CA (the last one, in case of subCAs)
377}
378
379//___________________________________________________________________________
381{
382 // Iterator functionality: init
383
384 previous = 0;
385 current = begin;
386 if (current)
387 return current->Cert();
388 return (XrdCryptoX509 *)0;
389}
390
391//___________________________________________________________________________
393{
394 // Iterator functionality: get next
395
397 if (current) {
398 current = current->Next();
399 if (current)
400 return current->Cert();
401 }
402 return (XrdCryptoX509 *)0;
403}
404
405//___________________________________________________________________________
407 ESearchMode mode)
408{
409 // Return first certificate in the chain with issuer
410 // Match according to mode.
411
412 XrdCryptoX509ChainNode *cn = FindIssuer(issuer, mode);
413
414 // We are done
415 return ((cn) ? cn->Cert() : (XrdCryptoX509 *)0);
416}
417
418//___________________________________________________________________________
420 ESearchMode mode)
421{
422 // Return first certificate in the chain with subject
423 // Match according to mode.
424
425 XrdCryptoX509ChainNode *cn = FindSubject(subject, mode);
426
427 // We are done
428 return ((cn) ? cn->Cert() : (XrdCryptoX509 *)0);
429
430}
431
432//___________________________________________________________________________
434 ESearchMode mode, XrdCryptoX509ChainNode **prev)
435{
436 // Return first chain node with certificate having issuer
437 // Match according to mode.
438
439 // Make sure we got something to compare
440 if (!issuer)
441 return (XrdCryptoX509ChainNode *)0;
442
446 XrdCryptoX509 *c = 0;
447 while (cn) {
448 n = cn->Next();
449 c = cn->Cert();
450 if(c) {
451 const char *pi = c->Issuer();
452 if (pi) {
453 if (mode == kExact) {
454 if (!strcmp(pi, issuer))
455 break;
456 } else if (mode == kBegin) {
457 if (strstr(pi, issuer) == c->Issuer())
458 break;
459 } else if (mode == kEnd) {
460 int ibeg = strlen(pi) - strlen(issuer);
461 if (!strcmp(pi + ibeg, issuer))
462 break;
463 }
464 }
465 }
466 c = 0;
467 cp = cn; // previous
468 cn = n;
469 }
470 // return previous, if requested
471 if (prev)
472 *prev = (cn) ? cp : 0;
473
474 // We are done
475 return ((cn) ? cn : (XrdCryptoX509ChainNode *)0);
476}
477
478//___________________________________________________________________________
480 ESearchMode mode, XrdCryptoX509ChainNode **prev)
481{
482 // Return first chain node with certificate having subject
483 // Match according to mode.
484
485 // Make sure we got something to compare
486 if (!subject)
487 return (XrdCryptoX509ChainNode *)0;
488
492 XrdCryptoX509 *c = 0;
493 while (cn) {
494 n = cn->Next();
495 c = cn->Cert();
496 const char *ps = c ? c->Subject() : 0;
497 if (c && ps) {
498 if (mode == kExact) {
499 if (!strcmp(ps, subject))
500 break;
501 } else if (mode == kBegin) {
502 if (strstr(ps, subject) == ps)
503 break;
504 } else if (mode == kEnd) {
505 int sbeg = strlen(ps) - strlen(subject);
506 if (!strcmp(ps + sbeg, subject))
507 break;
508 }
509 }
510 c = 0;
511 cp = cn; // previous
512 cn = n;
513 }
514 // return previous, if requested
515 if (prev)
516 *prev = (cn) ? cp : 0;
517
518 // We are done
519 return ((cn) ? cn : (XrdCryptoX509ChainNode *)0);
520}
521
522//___________________________________________________________________________
524{
525 // Dump content
526 EPNAME("X509Chain::Dump");
527
528 LOCDUMP("//------------------Dumping X509 chain content ------------------//");
529 LOCDUMP("//");
530 LOCDUMP("// Chain instance: "<<this);
531 LOCDUMP("//");
532 LOCDUMP("// Number of certificates: "<<Size());
533 LOCDUMP("//");
534 if (CAname()) {
535 LOCDUMP("// CA: "<<CAname());
536 } else {
537 LOCDUMP("// CA: absent");
538 }
539 if (EECname()) {
540 LOCDUMP("// EEC: "<<EECname());
541 } else {
542 LOCDUMP("// EEC: absent");
543 }
544 LOCDUMP("//");
547 while (c) {
548 n = c->Next();
549 if (c->Cert()) {
550 LOCDUMP("// Issuer: "<<c->Cert()->IssuerHash()<<
551 " Subject: "<<c->Cert()->SubjectHash()<<
552 " Type: "<<c->Cert()->Type());
553 }
554 c = n;
555 }
556 LOCDUMP("//");
557 LOCDUMP("//---------------------------- END ------------------------------//")
558}
559
560//___________________________________________________________________________
562{
563 // Reorder certificates in such a way that certificate n is the
564 // issuer of certificate n+1 .
565 // Return -1 if inconsistencies are found.
566 EPNAME("X509Chain::Reorder");
567
568 if (size < 2) {
569 DEBUG("Nothing to reorder (size: "<<size<<")");
570 // Search for the effective CA (the last one, in case of subCAs)
572 return 0;
573 }
574
575 // Loop over the certificates
576 XrdCryptoX509ChainNode *nc = 0, *np = 0, *nn = 0, *nr = 0, *npp = 0;
577
578 // Look for the first one, if needed
579 nr = begin;
580 np = nr;
581 while (nr) {
582 //
583 if (!(nn = FindSubject(nr->Cert()->Issuer(),kExact,&npp)) ||
584 nn == nr)
585 break;
586 np = nr;
587 nr = nr->Next();
588 }
589
590 // Move it in first position if not yet there
591 if (nr && nr != begin) {
592 np->SetNext(nr->Next()); // short cut old position
593 nr->SetNext(begin); // set our next to present begin
594 if (end == nr) // Update end
595 end = np;
596 begin = nr; // set us as begin
597 // Flag if not CA: we do not check validity here
598 if (nr->Cert()->type != XrdCryptoX509::kCA) {
600 } else if (caname.length() <= 0) {
601 // Set the CA properties only if not done already to avoid overwriting
602 // the result of previous analysis
603 caname = nr->Cert()->Subject();
604 cahash = nr->Cert()->SubjectHash();
606 }
607 }
608
609 int left = size-1;
610 np = begin;
611 while (np) {
612 if (np->Cert()) {
613 const char *pi = np->Cert()->Subject();
614 // Set the EEC name, if not yet done
615 if (np->Cert()->type == XrdCryptoX509::kEEC && eecname.length() <= 0) {
616 eecname = pi;
617 eechash = np->Cert()->SubjectHash();
618 }
619 npp = np;
620 nc = np->Next();
621 while (nc) {
622 if (nc->Cert() && !strcmp(pi, nc->Cert()->Issuer())) {
623 left--;
624 if (npp != np) {
625 npp->SetNext(nc->Next()); // drop child from previous pos
626 nc->SetNext(np->Next()); // set child next as our present
627 np->SetNext(nc); // set our next as child
628 if (nc == end)
629 end = npp;
630 }
631 break;
632 }
633 npp = nc;
634 nc = nc->Next();
635 }
636 }
637 np = np->Next();
638 }
639
640 // Search for the effective CA (the last one, in case of subCAs)
642
643 // Check consistency
644 if (left > 0) {
645 DEBUG("Inconsistency found: "<<left<<
646 " certificates could not be correctly enchained!");
647 return -1;
648 }
649
650 // We are done
651 return 0;
652}
653
654//___________________________________________________________________________
656{
657 // Search for the effective CA (the last one, in case of subCAs)
658 effca = 0; caname = ""; cahash = "";
659
661 while (np) {
662 if (np->Cert()) {
663 if (np->Cert()->type == XrdCryptoX509::kCA) {
664 if (!effca || (effca &&
665 !(strcmp(effca->Cert()->SubjectHash(),
666 np->Cert()->IssuerHash())))) effca = np;
667 }
668 }
669 np = np->Next();
670 }
671 if (effca && effca->Cert()) {
672 caname = effca->Cert()->Subject();
674 }
675}
676
677//___________________________________________________________________________
679{
680 // Verify cross signatures of the chain
681 EPNAME("X509Chain::Verify");
682 errcode = kNone;
683
684 // Do nothing if empty
685 if (size < 1) {
686 DEBUG("Nothing to verify (size: "<<size<<")");
687 return 0;
688 }
689
690 //
691 // Reorder if needed
692 if (Reorder() != 0) {
693 errcode = kInconsistent;
694 lastError = ":";
695 lastError += X509ChainError(errcode);
696 return 0;
697 }
698
699 //
700 // Verification options
701 int when = (vopt) ? vopt->when : (int)time(0);
702 int plen = (vopt) ? vopt->pathlen : -1;
703 bool chkss = (vopt) ? (vopt->opt & kOptsCheckSelfSigned) : 1;
704
705 //
706 // Global path depth length consistency check
707 if (plen > -1 && plen < size) {
708 errcode = kTooMany;
709 lastError = "checking path depth: ";
710 lastError += X509ChainError(errcode);
711 }
712
713 //
714 // Check the first certificate: it MUST be of CA type, valid,
715 // self-signed
716 if (!CheckCA(chkss)) {
717 errcode = kNoCA;
718 lastError = X509ChainError(errcode);
719 return 0;
720 }
721
722 //
723 // Analyse the rest
725 XrdCryptoX509 *xsig = node->Cert(); // Signing certificate
726 XrdCryptoX509 *xcer = 0; // Certificate under exam
727 node = node->Next();
728 while (node) {
729
730 // Attache to certificate
731 xcer = node->Cert();
732
733 // Standard verification
734 if (!Verify(errcode, "cert: ", XrdCryptoX509::kUnknown, when, xcer, xsig))
735 return 0;
736
737 // Get next
738 xsig = xcer;
739 node = node->Next();
740 }
741
742 // We are done (successfully!)
743 return 1;
744}
745
746//___________________________________________________________________________
747int XrdCryptoX509Chain::CheckValidity(bool outatfirst, int when)
748{
749 // Check validity at 'when' of certificates in the chain and return
750 // the number of invalid certificates.
751 // If 'outatfirst' return after the first invalid has been
752 // found.
753 EPNAME("X509Chain::CheckValidity");
754 int ninv = 0;
755
756 // Do nothing if empty
757 if (size < 1) {
758 DEBUG("Nothing to verify (size: "<<size<<")");
759 return ninv;
760 }
761
762 // Loop over the certificates
764 while (nc) {
765 //
766 XrdCryptoX509 *c = nc->Cert();
767 if (c) {
768 if (!(c->IsValid(when))) {
769 ninv++;
770 DEBUG("invalid certificate found");
771 if (outatfirst)
772 return ninv;
773 }
774 } else {
775 ninv++;
776 DEBUG("found node without certificate");
777 if (outatfirst)
778 return ninv;
779 }
780 // Get next
781 nc = nc->Next();
782 }
783
784 // We are done
785 return ninv;
786}
787
788//___________________________________________________________________________
789bool XrdCryptoX509Chain::Verify(EX509ChainErr &errcode, const char *msg,
790 XrdCryptoX509::EX509Type type, int when,
791 XrdCryptoX509 *xcer, XrdCryptoX509 *xsig,
792 XrdCryptoX509Crl *crl)
793{
794 // Internal verification method
795
796 // Certificate must be defined
797 if (!xcer) {
798 errcode = kNoCertificate;
799 lastError = msg;
800 lastError += X509ChainError(errcode);
801 return 0;
802 }
803
804 // Type should be the one expected
805 if (type != XrdCryptoX509::kUnknown && xcer->type != type) {
806 errcode = kInvalidType;
807 lastError = msg;
808 lastError += X509ChainError(errcode);
809 return 0;
810 }
811
812 // Must not be revoked (check only if required)
813 if (crl) {
814 // Get certificate serial number
815 XrdOucString sn = xcer->SerialNumberString();
816 if (crl->IsRevoked(sn.c_str(), when)) {
817 errcode = kRevoked;
818 lastError = msg;
819 lastError += X509ChainError(errcode);
820 return 0;
821 }
822 }
823
824 // Check validity in time
825 if (when >= 0 && !(xcer->IsValid(when))) {
826 errcode = kExpired;
827 lastError = msg;
828 lastError += X509ChainError(errcode);
829 return 0;
830 }
831
832 // Check signature
833 if (!xsig || !(xcer->Verify(xsig))) {
834 errcode = kVerifyFail;
835 lastError = msg;
836 lastError += X509ChainError(errcode);
837 return 0;
838 }
839
840 // We are done
841 return 1;
842}
843
844//_____________________________________________________________________________
846{
847 // Return subject name of the CA in the chain
848 EPNAME("X509Chain::CAname");
849
850 // If we do not have it already, try extraction
851 if (caname.length() <= 0 && statusCA == kUnknown) {
852
853 if (!CheckCA()) {
854 DEBUG("CA not found in chain");
855 return (const char *)0;
856 }
857 }
858
859 // return what we have
860 return (caname.length() > 0) ? caname.c_str() : (const char *)0;
861}
862
863//_____________________________________________________________________________
865{
866 // Return subject name of the EEC in the chain
867 EPNAME("X509Chain::EECname");
868
869 // If we do not have it already, try extraction
870 if (eecname.length() <= 0) {
871
873 while (c) {
874 if (c->Cert()->type == XrdCryptoX509::kEEC) {
875 eecname = c->Cert()->Subject();
876 break;
877 }
878 c = c->Next();
879 }
880 if (eecname.length() <= 0) {
881 DEBUG("EEC not found in chain");
882 return (const char *)0;
883 }
884 }
885
886 // return what we have
887 return (eecname.length() > 0) ? eecname.c_str() : (const char *)0;
888}
889
890//_____________________________________________________________________________
892{
893 // Return the subject name hash of the CA in the chain
894 EPNAME("X509Chain::CAhash");
895
896 // If we do not have it already, try extraction
897 if (cahash.length() <= 0 && statusCA == kUnknown) {
898
899 if (!CheckCA()) {
900 DEBUG("CA not found in chain");
901 return (const char *)0;
902 }
903 }
904
905 // return what we have
906 return (cahash.length() > 0) ? cahash.c_str() : (const char *)0;
907}
908
909//_____________________________________________________________________________
911{
912 // Return the subject name hash of the EEC in the chain
913 EPNAME("X509Chain::EEChash");
914
915 // If we do not have it already, try extraction
916 if (eechash.length() <= 0) {
917
919 while (c) {
920 if (c->Cert()->type == XrdCryptoX509::kEEC) {
921 eechash = c->Cert()->SubjectHash();
922 break;
923 }
924 c = c->Next();
925 }
926 if (eechash.length() <= 0) {
927 DEBUG("EEC not found in chain");
928 return (const char *)0;
929 }
930 }
931
932 // return what we have
933 return (eechash.length() > 0) ? eechash.c_str() : (const char *)0;
934}
#define DEBUG(x)
#define EPNAME(x)
#define LOCDUMP(y)
static const char * X509ChainErrStr[]
const int kOptsCheckSelfSigned
XrdCryptoX509 * Cert() const
XrdCryptoX509ChainNode * Next() const
void SetNext(XrdCryptoX509ChainNode *n)
virtual bool Verify(EX509ChainErr &e, x509ChainVerifyOpt_t *vopt=0)
void InsertAfter(XrdCryptoX509 *c, XrdCryptoX509 *cp)
bool CheckCA(bool checkselfsigned=1)
XrdCryptoX509 * Next()
virtual int CheckValidity(bool outatfirst=1, int when=0)
XrdCryptoX509ChainNode * end
const char * LastError() const
XrdCryptoX509 * Begin()
XrdCryptoX509ChainNode * FindIssuer(const char *issuer, ESearchMode mode=kExact, XrdCryptoX509ChainNode **p=0)
XrdCryptoX509 * EffCA() const
XrdCryptoX509ChainNode * FindSubject(const char *subject, ESearchMode mode=kExact, XrdCryptoX509ChainNode **p=0)
XrdCryptoX509ChainNode * begin
void Cleanup(bool keepCA=0)
void Remove(XrdCryptoX509 *c)
XrdCryptoX509 * SearchByIssuer(const char *issuer, ESearchMode mode=kExact)
ECAStatus StatusCA() const
XrdCryptoX509ChainNode * previous
XrdCryptoX509ChainNode * current
void PushBack(XrdCryptoX509 *c)
const char * X509ChainError(EX509ChainErr e)
XrdCryptoX509 * SearchBySubject(const char *subject, ESearchMode mode=kExact)
void PutInFront(XrdCryptoX509 *c)
XrdCryptoX509ChainNode * effca
XrdCryptoX509ChainNode * Find(XrdCryptoX509 *c)
XrdCryptoX509Chain(XrdCryptoX509 *c=0)
virtual bool IsRevoked(int serialnumber, int when)
virtual bool Verify(XrdCryptoX509 *ref)
virtual const char * Subject()
const char * Type(EX509Type t=kUnknown) const
virtual const char * SubjectHash(int)
virtual const char * IssuerHash(int)
virtual const char * Issuer()
virtual bool IsValid(int when=0)
virtual XrdOucString SerialNumberString()
int length() const
const char * c_str() const