#!/usr/bin/env ruby require 'open3' require 'openssl' require 'uri' USAGE = "usage: #{$PROGRAM_NAME} : #{$PROGRAM_NAME} https://[:port][path]" def die(msg) $stderr.puts(msg) exit 1 end die(USAGE) unless ARGV.length == 1 case ARGV[0] when %r{^https?://} uri = URI.parse(ARGV[0]) target = "#{uri.host}:#{uri.port}" when /[^:]+:[0-9]+/ target = ARGV[0] else die(USAGE) end s_client_args = ['openssl', 's_client', '-connect', target] stdout, stderr, status = Open3.capture3(*s_client_args, stdin_data: '') die(stderr) unless status.success? cert_text = stdout[/^-----BEGIN\sCERTIFICATE-----$ [a-zA-Z0-9+=\/\n]+ ^-----END\sCERTIFICATE-----$/mx] die("unexpected output: #{stdout}") unless cert_text hosts = [] cert = OpenSSL::X509::Certificate.new(cert_text) cn = cert.subject.to_a.find { |dn| dn[0] == 'CN' } hosts << cn[1] if cn && cn[1] san = cert.extensions.find { |ext| ext.oid == 'subjectAltName' } if san hosts += san.value.split(', ') .select { |item| item[/^DNS:/] } .map { |item| item.sub(/^DNS:/, '') } end puts hosts.uniq