Software / code / prosody
Comparison
plugins/mod_console.lua @ 3669:4b56cd1302d4
mod_console: Add s2s:showcert() command to show the certificate for a domain
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Sun, 28 Nov 2010 21:03:33 +0000 |
| parent | 3652:8ae10787272a |
| child | 3671:b7d5fe8eb829 |
comparison
equal
deleted
inserted
replaced
| 3668:29a340777d7b | 3669:4b56cd1302d4 |
|---|---|
| 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'"; |