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