@@ 86,7 86,7 @@ def check_generic(domain, port, timeout=5, starttls=False):
try:
chain = get_tls_certificate(domain, port, timeout=timeout, starttls=starttls)
except TimeoutError:
- return False, "Timeout"
+ return False, "Timeout", None
except OpenSSL.SSL.Error as e:
return False, str(e)
x509 = chain[0]
@@ 96,7 96,7 @@ def check_generic(domain, port, timeout=5, starttls=False):
cn = component[1].decode()
break
else:
- return False, "Certificate had no common name"
+ return False, "Certificate had no common name", chain
names = [cn]
@@ 122,7 122,7 @@ def check_generic(domain, port, timeout=5, starttls=False):
if re.match(name_regex, domain):
break
else:
- return False, f"Wrong CN, certificate is for {cn}"
+ return False, f"Wrong CN, certificate is for {cn}", chain
# TODO: If ocsp is True, verify ocsp
@@ 132,13 132,13 @@ def check_generic(domain, port, timeout=5, starttls=False):
time_left = not_after - now
if now < not_before:
- return False, f"Certificate is not yet valid (valid after {not_before})"
+ return False, f"Certificate is not yet valid (valid after {not_before})", chain
if now > not_after:
- return False, f"Certificate is expired (valid until {not_after})"
+ return False, f"Certificate is expired (valid until {not_after})", chain
if (not_after - now).days < 20:
- return None, f"Certificate almost expired ({time_left})"
+ return None, f"Certificate almost expired ({time_left})", chain
# Check the chain
store = get_store()
@@ 148,12 148,43 @@ def check_generic(domain, port, timeout=5, starttls=False):
except OpenSSL.crypto.X509StoreContextError as e:
errnum = e.args[0][0]
if errnum == 18:
- return False, "Certificate is self-signed"
+ return False, "Certificate is self-signed", chain
elif errnum == 19:
- return False, "Self-signed certificate in the certificate chain"
+ return False, "Self-signed certificate in the certificate chain", chain
return False, str(e)
- return True, f"Ok, {time_left.days} days remaining"
+ return True, f"Ok, {time_left.days} days remaining", chain
+
+
+def print_detail(chain):
+ result = []
+ x509 = chain[0]
+ subject = []
+ components = x509.get_subject().get_components()
+ for c in components:
+ subject.append(f'{c[0].decode()}={c[1].decode()}')
+ result.append(colorama.Fore.WHITE + 'subject: ' + colorama.Style.RESET_ALL + ' '.join(subject))
+
+ names = []
+ for i in range(0, x509.get_extension_count()):
+ ext = x509.get_extension(i)
+ if ext.get_short_name() == b'subjectAltName':
+ san = str(ext)
+ sans = san.split(', ')
+ for s in sans:
+ s_type, s_name = s.split(":", maxsplit=1)
+ if s_type == 'DNS':
+ names.append(s_name)
+ result.append(colorama.Fore.WHITE + 'alt names: ' + colorama.Style.RESET_ALL + ', '.join(names))
+ result.append(colorama.Fore.WHITE + f'serial: {colorama.Style.RESET_ALL} {x509.get_serial_number():x}')
+
+ issuer_name = x509.get_issuer()
+ issuer = []
+ for c in issuer_name.get_components():
+ issuer.append(f'{c[0].decode()}={c[1].decode()}')
+ result.append(colorama.Fore.WHITE + 'issuer: ' + colorama.Style.RESET_ALL + ' '.join(issuer))
+
+ return result
def main():
@@ 163,10 194,12 @@ def main():
parser.add_argument('--imaps', action=argparse.BooleanOptionalAction, default=False, help='Check imap (993)')
parser.add_argument('--pop3s', action=argparse.BooleanOptionalAction, default=False, help='Check pop3s (995)')
parser.add_argument('--smtps', action=argparse.BooleanOptionalAction, default=False, help='Check smtp (465)')
- parser.add_argument('--submission', action=argparse.BooleanOptionalAction, default=False, help='Check smtp with starttls (587)')
+ parser.add_argument('--submission', action=argparse.BooleanOptionalAction, default=False,
+ help='Check smtp with starttls (587)')
parser.add_argument('--port', action="append", help="Check a specific port", default=[], type=int)
parser.add_argument('--timeout', '-t', default=5, help='Set the timeout in seconds for the TCP connection',
type=int)
+ parser.add_argument('--verbose', '-v', action='store_true', help='Output detailed cert info')
args = parser.parse_args()
domain_len = len(max(args.domain, key=len))
@@ 220,6 253,14 @@ def main():
else:
print(colorama.Fore.YELLOW, result[1], colorama.Style.RESET_ALL)
+ if args.verbose:
+ lines = print_detail(result[2])
+ offset = domain_len + 3
+ if len(protolist) > 1:
+ offset += proto_len + 1
+ for line in lines:
+ print(' ' * offset + line)
+
exit(returncode)