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