XRootD
Loading...
Searching...
No Matches
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
63const char *XrdCryptosslX509::cpxytype[5] = { "", "unknown", "RFC", "GSI3", "legacy" };
64
65//_____________________________________________________________________________
66XrdCryptosslX509::XrdCryptosslX509(const char *cf, const char *kf)
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//_____________________________________________________________________________
319void 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;
377 XrdOucString emsg;
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//_____________________________________________________________________________
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//_____________________________________________________________________________
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//____________________________________________________________________________
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//____________________________________________________________________________
861int 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;
1068end:
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//____________________________________________________________________________
1078int 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);
1118err:
1119 BIO_free(bp);
1120 return(0);
1121}
1122
1123//____________________________________________________________________________
1124bool 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)
#define EPNAME(x)
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
const char * SubjectHash()
virtual XrdCryptoX509data Opaque()
const char * IssuerHash()
static bool MatchHostnames(const char *match_pattern, const char *fqdn)
const char * Issuer()
XrdCryptoX509data GetExtension(const char *oid)
const char * Subject()
int DumpExtensions(bool dumpunknown=0)
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)
kXR_int32 size