Skip to content

Instantly share code, notes, and snippets.

@ashafer01
Last active September 10, 2020 20:43
Show Gist options
  • Save ashafer01/a0e7be17a7239429f5519a6563361d90 to your computer and use it in GitHub Desktop.
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
#!/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