559 end |
559 end |
560 |
560 |
561 return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; |
561 return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; |
562 end |
562 end |
563 |
563 |
|
564 local function print_subject(print, subject) |
|
565 for _, entry in ipairs(subject) do |
|
566 print( |
|
567 (" %s: %q"):format( |
|
568 entry.name or entry.oid, |
|
569 entry.value:gsub("[\r\n%z%c]", " ") |
|
570 ) |
|
571 ); |
|
572 end |
|
573 end |
|
574 |
|
575 function def_env.s2s:showcert(domain) |
|
576 local ser = require "util.serialization".serialize; |
|
577 local print = self.session.print; |
|
578 local domain_sessions = set.new(array.collect(keys(incoming_s2s))) |
|
579 /function(session) return session.from_host == domain; end; |
|
580 for local_host in values(prosody.hosts) do |
|
581 local s2sout = local_host.s2sout; |
|
582 if s2sout and s2sout[domain] then |
|
583 domain_sessions:add(s2sout[domain]); |
|
584 end |
|
585 end |
|
586 local cert_set = {}; |
|
587 for session in domain_sessions do |
|
588 local conn = session.conn; |
|
589 conn = conn and conn:socket(); |
|
590 if not conn.getpeercertificate then |
|
591 if conn.dohandshake then |
|
592 error("This version of LuaSec does not support certificate viewing"); |
|
593 end |
|
594 else |
|
595 local cert = conn:getpeercertificate(); |
|
596 if cert then |
|
597 local digest = cert:digest("sha1"); |
|
598 if not cert_set[digest] then |
|
599 local chain_valid, chain_err = conn:getpeerchainvalid(); |
|
600 cert_set[digest] = { |
|
601 { |
|
602 from = session.from_host, |
|
603 to = session.to_host, |
|
604 direction = session.direction |
|
605 }; |
|
606 chain_valid = chain_valid; |
|
607 chain_err = chain_err; |
|
608 cert = cert; |
|
609 }; |
|
610 else |
|
611 table.insert(cert_set[digest], { |
|
612 from = session.from_host, |
|
613 to = session.to_host, |
|
614 direction = session.direction |
|
615 }); |
|
616 end |
|
617 end |
|
618 end |
|
619 end |
|
620 local domain_certs = array.collect(values(cert_set)); |
|
621 -- Phew. We now have a array of unique certificates presented by domain. |
|
622 local print = self.session.print; |
|
623 local n_certs = #domain_certs; |
|
624 |
|
625 if n_certs == 0 then |
|
626 return "No certificates found for "..domain; |
|
627 end |
|
628 |
|
629 local function _capitalize_and_colon(byte) |
|
630 return string.upper(byte)..":"; |
|
631 end |
|
632 local function pretty_fingerprint(hash) |
|
633 return hash:gsub("..", _capitalize_and_colon):sub(1, -2); |
|
634 end |
|
635 |
|
636 for cert_info in values(domain_certs) do |
|
637 local cert = cert_info.cert; |
|
638 print("---") |
|
639 print("Fingerprint (SHA1): "..pretty_fingerprint(cert:digest("sha1"))); |
|
640 print(""); |
|
641 local n_streams = #cert_info; |
|
642 print("Currently used on "..n_streams.." stream"..(n_streams==1 and "" or "s")..":"); |
|
643 for _, stream in ipairs(cert_info) do |
|
644 if stream.direction == "incoming" then |
|
645 print(" "..stream.to.." <- "..stream.from); |
|
646 else |
|
647 print(" "..stream.from.." -> "..stream.to); |
|
648 end |
|
649 end |
|
650 print(""); |
|
651 local chain_valid, err = cert_info.chain_valid, cert_info.chain_err; |
|
652 local valid_identity = cert_verify_identity(domain, "xmpp-server", cert); |
|
653 print("Trusted certificate: "..(chain_valid and "Yes" or ("No ("..err..")"))); |
|
654 print("Issuer: "); |
|
655 print_subject(print, cert:issuer()); |
|
656 print(""); |
|
657 print("Valid for "..domain..": "..(valid_identity and "Yes" or "No")); |
|
658 print("Subject:"); |
|
659 print_subject(print, cert:subject()); |
|
660 end |
|
661 print("---"); |
|
662 return ("Showing "..n_certs.." certificate" |
|
663 ..(n_certs==1 and "" or "s") |
|
664 .." presented by "..domain.."."); |
|
665 end |
|
666 |
564 function def_env.s2s:close(from, to) |
667 function def_env.s2s:close(from, to) |
565 local print, count = self.session.print, 0; |
668 local print, count = self.session.print, 0; |
566 |
669 |
567 if not (from and to) then |
670 if not (from and to) then |
568 return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; |
671 return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; |