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