~martijnbraam/certtool

b3d5063e0b41eec1d2e12f5e1e8488d87f73e206 — Martijn Braam 1 year, 23 days ago faf32f8
Implement starttls
1 files changed, 23 insertions(+), 9 deletions(-)

M certtool/__main__.py
M certtool/__main__.py => certtool/__main__.py +23 -9
@@ 66,9 66,13 @@ def check_ocsp(domain, port, chain):
        print(e)


def get_tls_certificate(domain, port, timeout=5):
def get_tls_certificate(domain, port, timeout=5, starttls=False):
    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD)
    conn = socket.create_connection((domain, port), timeout=timeout)
    if starttls:
        banner = conn.recv(1000)
        conn.send(b'EHLO\nSTARTTLS\n')
        leftover = conn.recv(1000)
    sock = OpenSSL.SSL.Connection(ctx, conn)
    sock.setblocking(True)
    sock.set_connect_state()


@@ 78,11 82,13 @@ def get_tls_certificate(domain, port, timeout=5):
    return chain


def check_generic(domain, port, timeout=5):
def check_generic(domain, port, timeout=5, starttls=False):
    try:
        chain = get_tls_certificate(domain, port, timeout=timeout)
        chain = get_tls_certificate(domain, port, timeout=timeout, starttls=starttls)
    except TimeoutError:
        return False, "Timeout"
    except OpenSSL.SSL.Error as e:
        return False, str(e)
    x509 = chain[0]
    components = x509.get_subject().get_components()
    for component in components:


@@ 153,10 159,11 @@ def check_generic(domain, port, timeout=5):
def main():
    parser = argparse.ArgumentParser("Certificate checker")
    parser.add_argument('domain', nargs='+')
    parser.add_argument('--https', action=argparse.BooleanOptionalAction, default=True, help='Check http')
    parser.add_argument('--imaps', action=argparse.BooleanOptionalAction, default=False, help='Check imap')
    parser.add_argument('--pop3s', action=argparse.BooleanOptionalAction, default=False, help='Check pop3s')
    parser.add_argument('--smtps', action=argparse.BooleanOptionalAction, default=False, help='Check smtp')
    parser.add_argument('--https', action=argparse.BooleanOptionalAction, default=True, help='Check http (443)')
    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('--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)


@@ 173,6 180,8 @@ def main():
        protolist.append('pop3s')
    if args.smtps:
        protolist.append('smtps')
    if args.submission:
        protolist.append('submission')
    protolist.extend(args.port)

    protocols = {


@@ 180,8 189,11 @@ def main():
        'imaps': 993,
        'pop3s': 995,
        'smtps': 465,
        'submission': 587,
    }

    proto_len = len(max(protolist, key=lambda l: len(str(l))))

    returncode = 0
    for domain in args.domain:
        print(domain.ljust(domain_len + 2), end='')


@@ 191,12 203,14 @@ def main():
            if len(protolist) > 1:
                if not first_proto:
                    print(' ' * (domain_len + 2), end='')
                print(f'{str(proto).ljust(5)} ', end='', flush=True)
                print(f'{str(proto).ljust(proto_len)} ', end='', flush=True)
            first_proto = False

            if isinstance(proto, str):
                proto = protocols[proto]
            result = check_generic(domain, proto, timeout=args.timeout)

            starttls = proto == 587
            result = check_generic(domain, proto, timeout=args.timeout, starttls=starttls)

            if result[0] is True:
                print(colorama.Fore.GREEN, result[1], colorama.Style.RESET_ALL)