XRootD
XrdCryptosslX509.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d C r y p t o s s l X 5 0 9 . 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 
29 /* ************************************************************************** */
30 /* */
31 /* OpenSSL implementation of XrdCryptoX509 */
32 /* */
33 /* ************************************************************************** */
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <cerrno>
38 #include <memory>
39 
44 
45 #include <openssl/pem.h>
46 
47 #define BIO_PRINT(b,c) \
48  BUF_MEM *bptr; \
49  BIO_get_mem_ptr(b, &bptr); \
50  if (bptr) { \
51  char *s = new char[bptr->length+1]; \
52  memcpy(s, bptr->data, bptr->length); \
53  s[bptr->length] = '\0'; \
54  PRINT(c << s); \
55  delete [] s; \
56  } else { \
57  PRINT("ERROR: "<<c<<" BIO internal buffer undefined!"); \
58  } \
59  if (b) BIO_free(b);
60 
61 const char *XrdCryptosslX509::cpxytype[5] = { "", "unknown", "RFC", "GSI3", "legacy" };
62 
63 //_____________________________________________________________________________
64 XrdCryptosslX509::XrdCryptosslX509(const char *cf, const char *kf)
65  : XrdCryptoX509()
66 {
67  // Constructor certificate from file 'cf'. If 'kf' is defined,
68  // complete the key of the certificate with the private key in kf.
69  EPNAME("X509::XrdCryptosslX509_file");
70 
71  // Init private members
72  cert = 0; // The certificate object
73  notbefore = -1; // begin-validity time in secs since Epoch
74  notafter = -1; // end-validity time in secs since Epoch
75  subject = ""; // subject;
76  issuer = ""; // issuer;
77  subjecthash = ""; // hash of subject;
78  issuerhash = ""; // hash of issuer;
79  subjectoldhash = ""; // hash of subject (md5 algorithm);
80  issueroldhash = ""; // hash of issuer (md5 algorithm);
81  srcfile = ""; // source file;
82  bucket = 0; // bucket for serialization
83  pki = 0; // PKI of the certificate
84  pxytype = 0; // Proxy sub-type
85 
86  // Make sure file name is defined;
87  if (!cf) {
88  DEBUG("file name undefined");
89  return;
90  }
91  // Make sure file exists;
92  struct stat st;
93  if (stat(cf, &st) != 0) {
94  if (errno == ENOENT) {
95  DEBUG("file "<<cf<<" does not exist - do nothing");
96  } else {
97  DEBUG("cannot stat file "<<cf<<" (errno: "<<errno<<")");
98  }
99  return;
100  }
101  //
102  // Open file in read mode
103  FILE *fc = fopen(cf, "r");
104  if (!fc) {
105  DEBUG("cannot open file "<<cf<<" (errno: "<<errno<<")");
106  return;
107  }
108  //
109  // Read the content:
110  if (!PEM_read_X509(fc, &cert, 0, 0)) {
111  DEBUG("Unable to load certificate from file");
112  return;
113  } else {
114  DEBUG("certificate successfully loaded");
115  }
116  //
117  // Close the file
118  fclose(fc);
119  //
120  // Save source file name
121  srcfile = cf;
122 
123  // Init some of the private members (the others upon need)
124  Subject();
125  Issuer();
126  CertType();
127 
128  // Get the public key
129  EVP_PKEY *evpp = 0;
130  // Read the private key file, if specified
131  if (kf) {
132  if (stat(kf, &st) == -1) {
133  DEBUG("cannot stat private key file "<<kf<<" (errno:"<<errno<<")");
134  return;
135  }
136  if (!S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) ||
137  (st.st_mode & (S_IROTH | S_IWOTH)) != 0 ||
138  (st.st_mode & (S_IWGRP)) != 0) {
139  DEBUG("private key file "<<kf<<" has wrong permissions "<<
140  (st.st_mode & 0777) << " (should be at most 0640)");
141  return;
142  }
143  // Open file in read mode
144  FILE *fk = fopen(kf, "r");
145  if (!fk) {
146  DEBUG("cannot open file "<<kf<<" (errno: "<<errno<<")");
147  return;
148  }
149  // This call fills the full key, i.e. also the public part (not really documented, though)
150  if ((evpp = PEM_read_PrivateKey(fk,0,0,0))) {
151  DEBUG("RSA key completed ");
152  // Test consistency
153  auto tmprsa = std::make_unique<XrdCryptosslRSA>(evpp, 1);
154  if (tmprsa->status == XrdCryptoRSA::kComplete) {
155  // Save it in pki
156  pki = tmprsa.release();
157  }
158  } else {
159  DEBUG("cannot read the key from file");
160  }
161  // Close the file
162  fclose(fk);
163  }
164  // If there were no private key or we did not manage to import it
165  // init pki with the partial key
166  if (!pki)
167  pki = new XrdCryptosslRSA(X509_get_pubkey(cert), 0);
168 }
169 
170 //_____________________________________________________________________________
172 {
173  // Constructor certificate from BIO 'bcer'
174  EPNAME("X509::XrdCryptosslX509_bio");
175 
176  // Init private members
177  cert = 0; // The certificate object
178  notbefore = -1; // begin-validity time in secs since Epoch
179  notafter = -1; // end-validity time in secs since Epoch
180  subject = ""; // subject;
181  issuer = ""; // issuer;
182  subjecthash = ""; // hash of subject;
183  issuerhash = ""; // hash of issuer;
184  subjectoldhash = ""; // hash of subject (md5 algorithm);
185  issueroldhash = ""; // hash of issuer (md5 algorithm);
186  srcfile = ""; // source file;
187  bucket = 0; // bucket for serialization
188  pki = 0; // PKI of the certificate
189  pxytype = 0; // Proxy sub-type
190 
191  // Make sure we got something;
192  if (!buck) {
193  DEBUG("got undefined opaque buffer");
194  return;
195  }
196 
197  //
198  // Create a bio_mem to store the certificates
199  BIO *bmem = BIO_new(BIO_s_mem());
200  if (!bmem) {
201  DEBUG("unable to create BIO for memory operations");
202  return;
203  }
204 
205  // Write data to BIO
206  int nw = BIO_write(bmem,(const void *)(buck->buffer),buck->size);
207  if (nw != buck->size) {
208  DEBUG("problems writing data to memory BIO (nw: "<<nw<<")");
209  return;
210  }
211 
212  // Get certificate from BIO
213  if (!(cert = PEM_read_bio_X509(bmem,0,0,0))) {
214  DEBUG("unable to read certificate to memory BIO");
215  return;
216  }
217  //
218  // Free BIO
219  BIO_free(bmem);
220 
221  //
222  // Init some of the private members (the others upon need)
223  Subject();
224  Issuer();
225  CertType();
226 
227  // Get the public key
228  EVP_PKEY *evpp = X509_get_pubkey(cert);
229  //
230  if (evpp) {
231  // init pki with the partial key
232  if (!pki)
233  pki = new XrdCryptosslRSA(evpp, 0);
234  } else {
235  DEBUG("could not access the public key");
236  }
237 }
238 
239 //_____________________________________________________________________________
241 {
242  // Constructor: import X509 object
243  EPNAME("X509::XrdCryptosslX509_x509");
244 
245  // Init private members
246  cert = 0; // The certificate object
247  notbefore = -1; // begin-validity time in secs since Epoch
248  notafter = -1; // end-validity time in secs since Epoch
249  subject = ""; // subject;
250  issuer = ""; // issuer;
251  subjecthash = ""; // hash of subject;
252  issuerhash = ""; // hash of issuer;
253  subjectoldhash = ""; // hash of subject (md5 algorithm);
254  issueroldhash = ""; // hash of issuer (md5 algorithm);
255  srcfile = ""; // source file;
256  bucket = 0; // bucket for serialization
257  pki = 0; // PKI of the certificate
258  pxytype = 0; // Proxy sub-type
259 
260  // Make sure we got something;
261  if (!xc) {
262  DEBUG("got undefined X509 object");
263  return;
264  }
265 
266  // Set certificate
267  cert = xc;
268 
269  //
270  // Init some of the private members (the others upon need)
271  Subject();
272  Issuer();
273  CertType();
274 
275  // Get the public key
276  EVP_PKEY *evpp = X509_get_pubkey(cert);
277  //
278  if (evpp) {
279  // init pki with the partial key
280  if (!pki)
281  pki = new XrdCryptosslRSA(evpp, 0);
282  } else {
283  DEBUG("could not access the public key");
284  }
285 }
286 
287 //_____________________________________________________________________________
289 {
290  // Destructor
291 
292  // Cleanup certificate
293  if (cert) X509_free(cert);
294  // Cleanup key
295  if (pki) delete pki;
296 }
297 
298 //_____________________________________________________________________________
299 void XrdCryptosslX509::CertType()
300 {
301  // Determine the certificate type
302  // Check the type of this certificate
303  EPNAME("X509::CertType");
304 
305  // Make sure we got something to look for
306  if (!cert) {
307  PRINT("ERROR: certificate is not initialized");
308  return;
309  }
310 
311  // Default for an initialized certificate
312  type = kEEC;
313 
314  // Are there any extension?
315  int numext = X509_get_ext_count(cert);
316  if (numext <= 0) {
317  DEBUG("certificate has got no extensions");
318  return;
319  }
320  TRACE(ALL,"certificate has "<<numext<<" extensions");
321 
322  bool done = 0;
323  // Check the extensions
324  X509_EXTENSION *ext = 0;
325  int idx = -1;
326 
327  // For CAs we are looking for a "basicConstraints"
328  int crit;
329  BASIC_CONSTRAINTS *bc = 0;
330  if ((bc = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(cert, NID_basic_constraints, &crit, &idx)) &&
331  bc->ca) {
332  type = kCA;
333  DEBUG("CA certificate");
334  done = 1;
335  }
336  if (bc) BASIC_CONSTRAINTS_free(bc);
337  if (done) return;
338 
339  // Is this a proxy?
340  idx = -1;
341  // Proxy names
342  XrdOucString common(subject, 0, subject.rfind("/CN=") - 1);
343  bool pxyname = 0;
344  if (issuer == common) {
345  pxyname = 1;
346  pxytype = 1;
347  }
348 
349  if (pxyname) {
350  type = kUnknown;
351  if ((idx = X509_get_ext_by_NID(cert, NID_proxyCertInfo,-1)) == -1) {
352  int xcp = -1;
354  if ((xcp = XrdCryptosslX509CheckProxy3(this, emsg)) == 0) {
355  type = kProxy;
356  pxytype = 3;
357  DEBUG("Found GSI 3 proxyCertInfo extension");
358  } else if (xcp == -1) {
359  PRINT("ERROR: "<<emsg);
360  }
361  } else {
362  if ((ext = X509_get_ext(cert,idx)) == 0) {
363  PRINT("ERROR: could not get proxyCertInfo extension");
364  }
365  }
366  }
367  if (ext) {
368  // RFC compliant or GSI 3 proxy
369  if (X509_EXTENSION_get_critical(ext)) {
370  PROXY_CERT_INFO_EXTENSION *pci = (PROXY_CERT_INFO_EXTENSION *)X509V3_EXT_d2i(ext);
371  if (pci != 0) {
372  if ((pci->proxyPolicy) != 0) {
373  if ((pci->proxyPolicy->policyLanguage) != 0) {
374  type = kProxy;
375  done = 1;
376  pxytype = 2;
377  DEBUG("Found RFC 382{0,1}compliant proxyCertInfo extension");
378  if (X509_get_ext_by_NID(cert, NID_proxyCertInfo, idx) != -1) {
379  PRINT("WARNING: multiple proxyCertInfo extensions found: taking the first");
380  }
381  } else {
382  PRINT("ERROR: accessing policy language from proxyCertInfo extension");
383  }
384  } else {
385  PRINT("ERROR: accessing policy from proxyCertInfo extension");
386  }
387  PROXY_CERT_INFO_EXTENSION_free(pci);
388  } else {
389  PRINT("ERROR: proxyCertInfo conversion error");
390  }
391  } else {
392  PRINT("ERROR: proxyCertInfo not flagged as critical");
393  }
394  }
395  if (!pxyname || done) return;
396 
397  // Check if GSI 2 legacy proxy
398  XrdOucString lastcn(subject, subject.rfind("/CN=") + 4, -1);
399  if (lastcn == "proxy" || lastcn == "limited proxy") {
400  pxytype = 4;
401  type = kProxy;
402  }
403 
404  // We are done
405  return;
406 }
407 
408 //_____________________________________________________________________________
410 {
411  // SetPKI:
412  // if newpki is null does nothing
413  // if newpki contains a consistent private & public key we take ownership
414  // so that this->PKI()->status will be kComplete.
415  // otherwise, newpki is not consistent:
416  // if the previous PKI() was null or was already kComplete it is and reset
417  // so that this->PKI()->status will be kInvalid.
418 
419  if (!newpki) return;
420 
421  auto tmprsa = std::make_unique<XrdCryptosslRSA>((EVP_PKEY*)newpki, 1);
422  if (!pki || pki->status == XrdCryptoRSA::kComplete ||
423  tmprsa->status == XrdCryptoRSA::kComplete) {
424  // Cleanup any existing key first
425  if (pki)
426  delete pki;
427 
428  // Set PKI
429  pki = tmprsa.release();
430  }
431 }
432 
433 //_____________________________________________________________________________
435 {
436  // Begin-validity time in secs since Epoch
437 
438  // If we do not have it already, try extraction
439  if (notbefore < 0) {
440  // Make sure we have a certificate
441  if (cert)
442  // Extract UTC time in secs from Epoch
443  notbefore = XrdCryptosslASN1toUTC(X509_get_notBefore(cert));
444  }
445  // return what we have
446  return notbefore;
447 }
448 
449 //_____________________________________________________________________________
451 {
452  // End-validity time in secs since Epoch
453 
454  // If we do not have it already, try extraction
455  if (notafter < 0) {
456  // Make sure we have a certificate
457  if (cert)
458  // Extract UTC time in secs from Epoch
459  notafter = XrdCryptosslASN1toUTC(X509_get_notAfter(cert));
460  }
461  // return what we have
462  return notafter;
463 }
464 
465 //_____________________________________________________________________________
467 {
468  // Return subject name
469  EPNAME("X509::Subject");
470 
471  // If we do not have it already, try extraction
472  if (subject.length() <= 0) {
473 
474  // Make sure we have a certificate
475  if (!cert) {
476  DEBUG("WARNING: no certificate available - cannot extract subject name");
477  return (const char *)0;
478  }
479 
480  // Extract subject name
481  XrdCryptosslNameOneLine(X509_get_subject_name(cert), subject);
482  }
483 
484  // return what we have
485  return (subject.length() > 0) ? subject.c_str() : (const char *)0;
486 }
487 
488 //_____________________________________________________________________________
490 {
491  // Return issuer name
492  EPNAME("X509::Issuer");
493 
494  // If we do not have it already, try extraction
495  if (issuer.length() <= 0) {
496 
497  // Make sure we have a certificate
498  if (!cert) {
499  DEBUG("WARNING: no certificate available - cannot extract issuer name");
500  return (const char *)0;
501  }
502 
503  // Extract issuer name
504  XrdCryptosslNameOneLine(X509_get_issuer_name(cert), issuer);
505  }
506 
507  // return what we have
508  return (issuer.length() > 0) ? issuer.c_str() : (const char *)0;
509 }
510 
511 //_____________________________________________________________________________
512 const char *XrdCryptosslX509::IssuerHash(int alg)
513 {
514  // Return hash of issuer name
515  // Use default algorithm (X509_NAME_hash) for alg = 0, old algorithm
516  // (for v>=1.0.0) when alg = 1
517  EPNAME("X509::IssuerHash");
518 
519 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(__APPLE__))
520  if (alg == 1) {
521  // md5 based
522  if (issueroldhash.length() <= 0) {
523  // Make sure we have a certificate
524  if (cert) {
525  char chash[30] = {0};
526  snprintf(chash, sizeof(chash),
527  "%08lx.0",X509_NAME_hash_old(X509_get_issuer_name(cert)));
528  issueroldhash = chash;
529  } else {
530  DEBUG("WARNING: no certificate available - cannot extract issuer hash (md5)");
531  }
532  }
533  // return what we have
534  return (issueroldhash.length() > 0) ? issueroldhash.c_str() : (const char *)0;
535  }
536 #else
537  if (alg == 1) { }
538 #endif
539 
540  // If we do not have it already, try extraction
541  if (issuerhash.length() <= 0) {
542 
543  // Make sure we have a certificate
544  if (cert) {
545  char chash[30] = {0};
546  snprintf(chash, sizeof(chash),
547  "%08lx.0",X509_NAME_hash(X509_get_issuer_name(cert)));
548  issuerhash = chash;
549  } else {
550  DEBUG("WARNING: no certificate available - cannot extract issuer hash (default)");
551  }
552  }
553 
554  // return what we have
555  return (issuerhash.length() > 0) ? issuerhash.c_str() : (const char *)0;
556 }
557 
558 //_____________________________________________________________________________
559 const char *XrdCryptosslX509::SubjectHash(int alg)
560 {
561  // Return hash of subject name
562  // Use default algorithm (X509_NAME_hash) for alg = 0, old algorithm
563  // (for v>=1.0.0) when alg = 1
564  EPNAME("X509::SubjectHash");
565 
566 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(__APPLE__))
567  if (alg == 1) {
568  // md5 based
569  if (subjectoldhash.length() <= 0) {
570  // Make sure we have a certificate
571  if (cert) {
572  char chash[30] = {0};
573  snprintf(chash, sizeof(chash),
574  "%08lx.0",X509_NAME_hash_old(X509_get_subject_name(cert)));
575  subjectoldhash = chash;
576  } else {
577  DEBUG("WARNING: no certificate available - cannot extract subject hash (md5)");
578  }
579  }
580  // return what we have
581  return (subjectoldhash.length() > 0) ? subjectoldhash.c_str() : (const char *)0;
582  }
583 #else
584  if (alg == 1) { }
585 #endif
586 
587  // If we do not have it already, try extraction
588  if (subjecthash.length() <= 0) {
589 
590  // Make sure we have a certificate
591  if (cert) {
592  char chash[30] = {0};
593  snprintf(chash, sizeof(chash),
594  "%08lx.0",X509_NAME_hash(X509_get_subject_name(cert)));
595  subjecthash = chash;
596  } else {
597  DEBUG("WARNING: no certificate available - cannot extract subject hash (default)");
598  }
599  }
600 
601  // return what we have
602  return (subjecthash.length() > 0) ? subjecthash.c_str() : (const char *)0;
603 }
604 
605 //_____________________________________________________________________________
607 {
608  // Return serial number as a kXR_int64
609 
610  kXR_int64 sernum = -1;
611  if (cert && X509_get_serialNumber(cert)) {
612  BIGNUM *bn = BN_new();
613  ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
614  char *sn = BN_bn2dec(bn);
615  sernum = strtoll(sn, 0, 10);
616  BN_free(bn);
617  OPENSSL_free(sn);
618  }
619 
620  return sernum;
621 }
622 
623 //_____________________________________________________________________________
625 {
626  // Return serial number as a hex string
627 
628  XrdOucString sernum;
629  if (cert && X509_get_serialNumber(cert)) {
630  BIGNUM *bn = BN_new();
631  ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), bn);
632  char *sn = BN_bn2hex(bn);
633  sernum = sn;
634  BN_free(bn);
635  OPENSSL_free(sn);
636  }
637 
638  return sernum;
639 }
640 
641 //_____________________________________________________________________________
643 {
644  // Return pointer to extension with OID oid, if any, in
645  // opaque form
646  EPNAME("X509::GetExtension");
647  XrdCryptoX509data ext = 0;
648 
649  // Make sure we got something to look for
650  if (!oid) {
651  DEBUG("OID string not defined");
652  return ext;
653  }
654 
655  // Make sure we got something to look for
656  if (!cert) {
657  DEBUG("certificate is not initialized");
658  return ext;
659  }
660 
661  // Are there any extension?
662  int numext = X509_get_ext_count(cert);
663  if (numext <= 0) {
664  DEBUG("certificate has got no extensions");
665  return ext;
666  }
667  DEBUG("certificate has "<<numext<<" extensions");
668 
669  // If the string is the Standard Name of a known extension check
670  // searche the corresponding NID
671  int nid = OBJ_sn2nid(oid);
672  bool usenid = (nid > 0);
673 
674  // Loop to identify the one we would like
675  int i = 0;
676  X509_EXTENSION *wext = 0;
677  for (i = 0; i< numext; i++) {
678  wext = X509_get_ext(cert, i);
679  if (usenid) {
680  int enid = OBJ_obj2nid(X509_EXTENSION_get_object(wext));
681  if (enid == nid)
682  break;
683  } else {
684  // Try matching of the text
685  char s[256];
686  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(wext), 1);
687  if (!strcmp(s, oid))
688  break;
689  }
690  // Do not free the extension: its owned by the certificate
691  wext = 0;
692  }
693 
694  // We are done if nothing was found
695  if (!wext) {
696  DEBUG("Extension "<<oid<<" not found");
697  return ext;
698  }
699 
700  // We are done
701  return (XrdCryptoX509data)wext;
702 }
703 
704 //_____________________________________________________________________________
706 {
707  // Export in form of bucket
708  EPNAME("X509::Export");
709 
710  // If we have already done it, return the previous result
711  if (bucket) {
712  DEBUG("serialization already performed:"
713  " return previous result ("<<bucket->size<<" bytes)");
714  return bucket;
715  }
716 
717  // Make sure we got something to export
718  if (!cert) {
719  DEBUG("certificate is not initialized");
720  return 0;
721  }
722 
723  //
724  // Now we create a bio_mem to serialize the certificate
725  BIO *bmem = BIO_new(BIO_s_mem());
726  if (!bmem) {
727  DEBUG("unable to create BIO for memory operations");
728  return 0;
729  }
730 
731  // Write certificate to BIO
732  if (!PEM_write_bio_X509(bmem, cert)) {
733  DEBUG("unable to write certificate to memory BIO");
734  return 0;
735  }
736 
737  // Extract pointer to BIO data and length of segment
738  char *bdata = 0;
739  int blen = BIO_get_mem_data(bmem, &bdata);
740  DEBUG("BIO data: "<<blen<<" bytes at 0x"<<(int *)bdata);
741 
742  // create the bucket now
743  bucket = new XrdSutBucket(0,0,kXRS_x509);
744  if (bucket) {
745  // Fill bucket
746  bucket->SetBuf(bdata, blen);
747  DEBUG("result of serialization: "<<bucket->size<<" bytes");
748  } else {
749  DEBUG("unable to create bucket for serialized format");
750  BIO_free(bmem);
751  return 0;
752  }
753  //
754  // Free BIO
755  BIO_free(bmem);
756  //
757  // We are done
758  return bucket;
759 }
760 
761 //_____________________________________________________________________________
763 {
764  // Verify certificate signature with pub key of ref cert
765  EPNAME("X509::Verify");
766 
767  // We must have been initialized
768  if (!cert)
769  return 0;
770 
771  // We must have something to check with
772  X509 *r = ref ? (X509 *)(ref->Opaque()) : 0;
773  EVP_PKEY *rk = r ? X509_get_pubkey(r) : 0;
774  if (!rk)
775  return 0;
776 
777  // Ok: we can verify
778  int rc = X509_verify(cert, rk);
779  EVP_PKEY_free(rk);
780  if (rc <= 0) {
781  if (rc == 0) {
782  // Signatures are not OK
783  DEBUG("signature not OK");
784  } else {
785  // General failure
786  DEBUG("could not verify signature");
787  }
788  return 0;
789  }
790  // Success
791  return 1;
792 }
793 
794 //____________________________________________________________________________
795 int XrdCryptosslX509::DumpExtensions(bool dumpunknown)
796 {
797  // Dump our extensions, if any
798  // Returns -1 on failure, 0 on success
799  EPNAME("DumpExtensions");
800 
801  int rc = -1;
802  // Point to the cerificate
803  X509 *xpi = (X509 *) Opaque();
804 
805  // Make sure we got the right inputs
806  if (!xpi) {
807  PRINT("we are empty! Do nothing");
808  return rc;
809  }
810 
811  rc = 1;
812  // Go through the extensions
813  X509_EXTENSION *xpiext = 0;
814  int npiext = X509_get_ext_count(xpi);
815  PRINT("found "<<npiext<<" extensions ");
816  int i = 0;
817  for (i = 0; i< npiext; i++) {
818  xpiext = X509_get_ext(xpi, i);
819  char s[256];
820  OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(xpiext), 1);
821  int crit = X509_EXTENSION_get_critical(xpiext);
822  // Notify what we found
823  PRINT(i << ": found extension '"<<s<<"', critical: " << crit);
824  // Dump its content
825  rc = 0;
826  XRDGSI_CONST unsigned char *pp = (XRDGSI_CONST unsigned char *) X509_EXTENSION_get_data(xpiext)->data;
827  long length = X509_EXTENSION_get_data(xpiext)->length;
828  int ret = FillUnknownExt(&pp, length, dumpunknown);
829  PRINT("ret: " << ret);
830  }
831 
832  // Done
833  return rc;
834 }
835 
836 //____________________________________________________________________________
837 int XrdCryptosslX509::FillUnknownExt(XRDGSI_CONST unsigned char **pp, long length, bool dump)
838 {
839  // Do the actual filling of the bio; can be called recursevely
840  EPNAME("FillUnknownExt");
841 
842  XRDGSI_CONST unsigned char *p,*ep,*tot,*op,*opp;
843  long len;
844  int tag, xclass, ret = 0;
845  int nl,hl,j,r;
846  ASN1_OBJECT *o = 0;
847  ASN1_OCTET_STRING *os = 0;
848  /* ASN1_BMPSTRING *bmp=NULL;*/
849  int dump_indent = 6;
850  int depth = 0;
851  int indent = 0;
852 
853  p = *pp;
854  tot = p + length;
855  op = p - 1;
856  while ((p < tot) && (op < p)) {
857  op = p;
858  j = ASN1_get_object(&p, &len, &tag, &xclass, length);
859 #ifdef LINT
860  j = j;
861 #endif
862  if (j & 0x80) {
863  if (dump) PRINT("ERROR: error in encoding");
864  ret = 0;
865  goto end;
866  }
867  hl = (p-op);
868  length -= hl;
869  /* if j == 0x21 it is a constructed indefinite length object */
870 
871  if (j != (V_ASN1_CONSTRUCTED | 1)) {
872  if (dump) PRINT("PRIM: d="<<depth<<" hl="<<hl<<" l="<<len);
873  } else {
874  if (dump) PRINT("CONST: d="<<depth<<" hl="<<hl<<" l=inf ");
875  }
876  if (!Asn1PrintInfo(tag, xclass, j, (indent) ? depth : 0))
877  goto end;
878  if (j & V_ASN1_CONSTRUCTED) {
879  ep = p + len;
880  if (dump) PRINT(" ");
881  if (len > length) {
882  if (dump) PRINT("ERROR:CONST: length is greater than " <<length);
883  ret=0;
884  goto end;
885  }
886  if ((j == 0x21) && (len == 0)) {
887  for (;;) {
888  r = FillUnknownExt(&p, (long)(tot-p), dump);
889  if (r == 0) {
890  ret = 0;
891  goto end;
892  }
893  if ((r == 2) || (p >= tot))
894  break;
895  }
896  } else {
897  while (p < ep) {
898  r = FillUnknownExt(&p, (long)len, dump);
899  if (r == 0) {
900  ret = 0;
901  goto end;
902  }
903  }
904  }
905  } else if (xclass != 0) {
906  p += len;
907  if (dump) PRINT(" ");
908  } else {
909  nl = 0;
910  if ((tag == V_ASN1_PRINTABLESTRING) ||
911  (tag == V_ASN1_T61STRING) ||
912  (tag == V_ASN1_IA5STRING) ||
913  (tag == V_ASN1_VISIBLESTRING) ||
914  (tag == V_ASN1_NUMERICSTRING) ||
915  (tag == V_ASN1_UTF8STRING) ||
916  (tag == V_ASN1_UTCTIME) ||
917  (tag == V_ASN1_GENERALIZEDTIME)) {
918  if (len > 0) {
919  char *s = new char[len + 1];
920  memcpy(s, p, len);
921  s[len] = 0;
922  if (dump) PRINT("GENERIC:" << s <<" (len: "<<(int)len<<")");
923  delete [] s;
924  } else {
925  if (dump) PRINT("GENERIC: (len: "<<(int)len<<")");
926  }
927  } else if (tag == V_ASN1_OBJECT) {
928  opp = op;
929  if (d2i_ASN1_OBJECT(&o, &opp, len+hl)) {
930  BIO *mem = BIO_new(BIO_s_mem());
931  i2a_ASN1_OBJECT(mem, o);
932  XrdOucString objstr;
933  if (dump) { BIO_PRINT(mem, "AOBJ:"); }
934  } else {
935  if (dump) PRINT("ERROR:AOBJ: BAD OBJECT");
936  }
937  } else if (tag == V_ASN1_BOOLEAN) {
938  if (len != 1) {
939  if (dump) PRINT("ERROR:BOOL: Bad boolean");
940  goto end;
941  }
942  if (dump) PRINT("BOOL:"<< p[0]);
943  } else if (tag == V_ASN1_BMPSTRING) {
944  /* do the BMP thang */
945  } else if (tag == V_ASN1_OCTET_STRING) {
946  int i, printable = 1;
947  opp = op;
948  os = d2i_ASN1_OCTET_STRING(0, &opp, len + hl);
949  if (os && os->length > 0) {
950  opp = os->data;
951  /* testing whether the octet string is * printable */
952  for (i=0; i<os->length; i++) {
953  if (( (opp[i] < ' ') && (opp[i] != '\n') &&
954  (opp[i] != '\r') && (opp[i] != '\t')) || (opp[i] > '~')) {
955  printable = 0;
956  break;
957  }
958  }
959  if (printable) {
960  /* printable string */
961  char *s = new char[os->length + 1];
962  memcpy(s, opp, os->length);
963  s[os->length] = 0;
964  if (dump) PRINT("OBJS:" << s << " (len: "<<os->length<<")");
965  delete [] s;
966  } else {
967  /* print the normal dump */
968  if (!nl) PRINT("OBJS:");
969  BIO *mem = BIO_new(BIO_s_mem());
970  if (BIO_dump_indent(mem, (const char *)opp, os->length, dump_indent) <= 0) {
971  if (dump) PRINT("ERROR:OBJS: problems dumping to BIO");
972  BIO_free(mem);
973  goto end;
974  }
975  if (dump) { BIO_PRINT(mem, "OBJS:"); }
976  nl = 1;
977  }
978  }
979  if (os) {
980  ASN1_OCTET_STRING_free(os);
981  os = 0;
982  }
983  } else if (tag == V_ASN1_INTEGER) {
984  ASN1_INTEGER *bs;
985  int i;
986 
987  opp = op;
988  bs = d2i_ASN1_INTEGER(0, &opp, len+hl);
989  if (bs) {
990  if (dump) PRINT("AINT:");
991  if (bs->type == V_ASN1_NEG_INTEGER)
992  if (dump) PRINT("-");
993  BIO *mem = BIO_new(BIO_s_mem());
994  for (i = 0; i < bs->length; i++) {
995  if (BIO_printf(mem, "%02X", bs->data[i]) <= 0) {
996  if (dump) PRINT("ERROR:AINT: problems printf-ing to BIO");
997  BIO_free(mem);
998  goto end;
999  }
1000  }
1001  if (dump) { BIO_PRINT(mem, "AINT:"); }
1002  if (bs->length == 0) PRINT("00");
1003  } else {
1004  if (dump) PRINT("ERROR:AINT: BAD INTEGER");
1005  }
1006  ASN1_INTEGER_free(bs);
1007  } else if (tag == V_ASN1_ENUMERATED) {
1008  ASN1_ENUMERATED *bs;
1009  int i;
1010 
1011  opp = op;
1012  bs = d2i_ASN1_ENUMERATED(0, &opp, len+hl);
1013  if (bs) {
1014  if (dump) PRINT("AENU:");
1015  if (bs->type == V_ASN1_NEG_ENUMERATED)
1016  if (dump) PRINT("-");
1017  BIO *mem = BIO_new(BIO_s_mem());
1018  for (i = 0; i < bs->length; i++) {
1019  if (BIO_printf(mem, "%02X", bs->data[i]) <= 0) {
1020  if (dump) PRINT("ERROR:AENU: problems printf-ing to BIO");
1021  BIO_free(mem);
1022  goto end;
1023  }
1024  }
1025  if (dump) { BIO_PRINT(mem, "AENU:"); }
1026  if (bs->length == 0) PRINT("00");
1027  } else {
1028  if (dump) PRINT("ERROR:AENU: BAD ENUMERATED");
1029  }
1030  ASN1_ENUMERATED_free(bs);
1031  }
1032 
1033  if (!nl && dump) PRINT(" ");
1034 
1035  p += len;
1036  if ((tag == V_ASN1_EOC) && (xclass == 0)) {
1037  ret = 2; /* End of sequence */
1038  goto end;
1039  }
1040  }
1041  length -= len;
1042  }
1043  ret = 1;
1044 end:
1045  if (o) ASN1_OBJECT_free(o);
1046  if (os) ASN1_OCTET_STRING_free(os);
1047  *pp = p;
1048  if (dump) PRINT("ret: "<<ret);
1049 
1050  return ret;
1051 }
1052 
1053 //____________________________________________________________________________
1054 int XrdCryptosslX509::Asn1PrintInfo(int tag, int xclass, int constructed, int indent)
1055 {
1056  // Print the BIO content
1057  EPNAME("Asn1PrintInfo");
1058 
1059  static const char fmt[]="%-18s";
1060  static const char fmt2[]="%2d %-15s";
1061  char str[128];
1062  const char *p, *p2 = 0;
1063 
1064  BIO *bp = BIO_new(BIO_s_mem());
1065  if (constructed & V_ASN1_CONSTRUCTED)
1066  p = "cons: ";
1067  else
1068  p = "prim: ";
1069  if (BIO_write(bp, p, 6) < 6)
1070  goto err;
1071  BIO_indent(bp, indent, 128);
1072 
1073  p = str;
1074  if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
1075  BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag);
1076  else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
1077  BIO_snprintf(str,sizeof str,"cont [ %d ]",tag);
1078  else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
1079  BIO_snprintf(str,sizeof str,"appl [ %d ]",tag);
1080  else if (tag > 30)
1081  BIO_snprintf(str,sizeof str,"<ASN1 %d>",tag);
1082  else
1083  p = ASN1_tag2str(tag);
1084 
1085  if (p2) {
1086  if (BIO_printf(bp,fmt2,tag,p2) <= 0)
1087  goto err;
1088  } else {
1089  if (BIO_printf(bp, fmt, p) <= 0)
1090  goto err;
1091  }
1092  BIO_PRINT(bp, "A1PI:");
1093  return(1);
1094 err:
1095  BIO_free(bp);
1096  return(0);
1097 }
1098 
1099 //____________________________________________________________________________
1100 bool XrdCryptosslX509::MatchesSAN(const char *fqdn, bool &hasSAN)
1101 {
1102  EPNAME("MatchesSAN");
1103 
1104  // Statically allocated array for hostname lengths. RFC1035 limits
1105  // valid lengths to 255 characters.
1106  char san_fqdn[256];
1107 
1108  // Assume we have no SAN extension. Failure may allow the caller to try
1109  // using the common name before giving up.
1110  hasSAN = false;
1111 
1112  GENERAL_NAMES *gens = static_cast<GENERAL_NAMES *>(X509_get_ext_d2i(cert,
1113  NID_subject_alt_name, NULL, NULL));
1114  if (!gens)
1115  return false;
1116 
1117  // Only an EEC is usable as a host certificate.
1118  if (type != kEEC)
1119  return false;
1120 
1121  // All failures are under the notion that we have a SAN extension.
1122  hasSAN = true;
1123 
1124  if (!fqdn)
1125  return false;
1126 
1127  bool success = false;
1128  for (int idx = 0; idx < sk_GENERAL_NAME_num(gens); idx++) {
1129  GENERAL_NAME *gen;
1130  ASN1_STRING *cstr;
1131  gen = sk_GENERAL_NAME_value(gens, idx);
1132  if (gen->type != GEN_DNS)
1133  continue;
1134  cstr = gen->d.dNSName;
1135  if (ASN1_STRING_type(cstr) != V_ASN1_IA5STRING)
1136  continue;
1137  int san_fqdn_len = ASN1_STRING_length(cstr);
1138  if (san_fqdn_len > 255)
1139  continue;
1140 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
1141  memcpy(san_fqdn, ASN1_STRING_get0_data(cstr), san_fqdn_len);
1142 #else
1143  memcpy(san_fqdn, ASN1_STRING_data(cstr), san_fqdn_len);
1144 #endif
1145  san_fqdn[san_fqdn_len] = '\0';
1146  if (strlen(san_fqdn) != static_cast<size_t>(san_fqdn_len)) // Avoid embedded null's.
1147  continue;
1148  DEBUG("Comparing SAN " << san_fqdn << " with " << fqdn);
1149  if (MatchHostnames(san_fqdn, fqdn)) {
1150  DEBUG("SAN " << san_fqdn << " matches with " << fqdn);
1151  success = true;
1152  break;
1153  }
1154  }
1155  sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
1156  return success;
1157 }
long long kXR_int64
Definition: XPtypes.hh:98
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
void * XrdCryptoX509data
void XrdCryptosslNameOneLine(X509_NAME *nm, XrdOucString &s)
time_t XrdCryptosslASN1toUTC(const ASN1_TIME *tsn1)
int XrdCryptosslX509CheckProxy3(XrdCryptoX509 *, XrdOucString &)
#define PRINT(y)
#define BIO_PRINT(b, c)
#define XRDGSI_CONST
int stat(const char *path, struct stat *buf)
int fclose(FILE *stream)
#define fopen(a, b)
Definition: XrdPosix.hh:49
int emsg(int rc, char *msg)
@ kXRS_x509
Definition: XrdSutAux.hh:79
#define TRACE(act, x)
Definition: XrdTrace.hh:63
ERSAStatus status
Definition: XrdCryptoRSA.hh:58
const char * IssuerHash()
virtual XrdCryptoX509data Opaque()
const char * SubjectHash()
static bool MatchHostnames(const char *match_pattern, const char *fqdn)
EX509Type type
const char * Issuer()
XrdCryptoX509data GetExtension(const char *oid)
const char * Subject()
kXR_int64 SerialNumber()
int DumpExtensions(bool dumpunknown=0)
virtual ~XrdCryptosslX509()
XrdOucString SerialNumberString()
XrdCryptoX509data Opaque()
bool Verify(XrdCryptoX509 *ref)
XrdSutBucket * Export()
virtual bool MatchesSAN(const char *, bool &)
XrdCryptosslX509(const char *cf, const char *kf=0)
void SetPKI(XrdCryptoX509data pki)
const char * c_str() const
int rfind(const char c, int start=STR_NPOS)
int length() const
kXR_int32 size
Definition: XrdSutBucket.hh:47
int SetBuf(const char *nb=0, int ns=0)