Last active
September 10, 2020 20:43
-
-
Save ashafer01/a0e7be17a7239429f5519a6563361d90 to your computer and use it in GitHub Desktop.
Runs `openssl s_client -showcerts` to obtain the certificate chain being presented by a remote server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Usage: get-remote-cert.py <host:port> [cert index] | |
Runs `openssl s_client -showcerts` to obtain the certificate chain being | |
presented by a remote server. | |
The default behavior (with cert index omitted) is to print all of the certificates | |
found in the s_client output to stdout. Any stderr output from s_client will be | |
printed seperately to stderr. | |
If the 1-based cert index is included, only that certificate will be output to | |
stdout. stderr behavior is unchanged. | |
This is designed to be piped to `openssl x509` to further decode the cert, | |
for example: | |
``` | |
% ./get-remote-cert.py example.com:443 1 | openssl x509 -in /dev/stdin -noout -subject -enddate | |
subject= /OU=Domain Control Validated/OU=EssentialSSL/CN=example.com | |
notAfter=Apr 05 23:59:59 2063 GMT | |
``` | |
The `openssl x509` tool provides a variety of options to drill down to the specific | |
information you need from the certificate. Note that on some systems, the openssl | |
manpages are available only using the subcommand, e.g. `man x509` or `man s_client`. | |
""" | |
import sys | |
from subprocess import Popen, PIPE | |
def main(): | |
try: | |
connect_str = sys.argv[1] | |
except IndexError: | |
print('Must pass host:port to pass to `openssl s_client -connect`', file=sys.stderr) | |
sys.exit(99) | |
try: | |
cert_index = int(sys.argv[2]) - 1 | |
except IndexError: | |
cert_index = None | |
except ValueError: | |
print('2nd argument must be 1-based index of the cert to print', file=sys.stderr) | |
sys.exit(99) | |
p = Popen(['openssl', 's_client', '-showcerts', '-connect', connect_str], | |
stdout=PIPE, stderr=PIPE, stdin=PIPE) | |
stdout, stderr = p.communicate(b'') | |
if stderr: | |
print('== begin stderr ==', file=sys.stderr) | |
sys.stderr.buffer.write(stderr) | |
print('== end stderr ==', file=sys.stderr) | |
this_cert = [] | |
certs = [] | |
for line in stdout.decode('utf-8').splitlines(): | |
if line.startswith('-----BEGIN ') and line.endswith('-----') or this_cert: | |
this_cert.append(line) | |
if line.startswith('-----END ') and line.endswith('-----'): | |
certs.append('\n'.join(this_cert)) | |
this_cert = [] | |
if this_cert: | |
certs.append('\n'.join(this_cert)) | |
if cert_index is None: | |
for cert in certs: | |
print(cert) | |
else: | |
print(certs[cert_index]) | |
sys.exit(p.returncode) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment